From 3fdd24aea06a9bf38d9d34fb8bccbb7023ed3100 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sat, 13 Dec 2008 12:21:03 +0100 Subject: Fork libiphone and remove anything non plist specific. Update library and make related files acordingly . --- AUTHORS | 7 +- Makefile.am | 4 +- README | 96 +--- configure.ac | 25 +- dev/Makefile.am | 24 - dev/afccheck.c | 134 ------ dev/lckdclient.c | 101 ---- dev/main.c | 154 ------ dev/plutil.c | 118 ----- dev/plutil.h | 13 - fdi/31-apple-mobile-device.fdi | 15 - fdi/Makefile.am | 3 - include/Makefile.am | 2 +- include/libiphone/libiphone.h | 127 ----- include/plist/plist.h | 39 ++ libiphone-1.0.pc.in | 12 - libplist-1.0.pc.in | 12 + src/AFC.c | 1018 ---------------------------------------- src/AFC.h | 77 --- src/Makefile.am | 16 +- src/initconf.c | 213 --------- src/iphone.c | 247 ---------- src/iphone.h | 45 -- src/lockdown.c | 969 -------------------------------------- src/lockdown.h | 62 --- src/usbmux.c | 381 --------------- src/usbmux.h | 58 --- src/userpref.c | 285 ----------- src/userpref.h | 71 --- 29 files changed, 68 insertions(+), 4260 deletions(-) delete mode 100644 dev/Makefile.am delete mode 100644 dev/afccheck.c delete mode 100644 dev/lckdclient.c delete mode 100644 dev/main.c delete mode 100644 dev/plutil.c delete mode 100644 dev/plutil.h delete mode 100644 fdi/31-apple-mobile-device.fdi delete mode 100644 fdi/Makefile.am delete mode 100644 include/libiphone/libiphone.h create mode 100644 include/plist/plist.h delete mode 100644 libiphone-1.0.pc.in create mode 100644 libplist-1.0.pc.in delete mode 100644 src/AFC.c delete mode 100644 src/AFC.h delete mode 100644 src/initconf.c delete mode 100644 src/iphone.c delete mode 100644 src/iphone.h delete mode 100644 src/lockdown.c delete mode 100644 src/lockdown.h delete mode 100644 src/usbmux.c delete mode 100644 src/usbmux.h delete mode 100644 src/userpref.c delete mode 100644 src/userpref.h diff --git a/AUTHORS b/AUTHORS index 18eedb0..ae1defd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,8 +1,3 @@ Zach C. Jonathan Beck -Matt Colyer -Martin Aumueller -Christophe Fergeau -Martin S. -Paul Sladen -Patrick Walton + diff --git a/Makefile.am b/Makefile.am index f103377..ccd5781 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,9 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = src include fdi $(DEV_SUB) +SUBDIRS = src include pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libiphone-1.0.pc +pkgconfig_DATA = libplist-1.0.pc doc: doxygen doxygen.cfg diff --git a/README b/README index 472547f..e83ea2f 100644 --- a/README +++ b/README @@ -2,13 +2,9 @@ INSTALLATION ================================================================================ For: - Apple iPhone/iPod Touch 1.0/1.1/1.1.1/1.2/1.3/2.0+ - + iPod USB cable + Apple Binary and XML Property Lists You must have: - libgnutls-dev - libusb-dev - libfuse-dev (and the associated kernel modules) libglib2.0-dev libxml2-dev make @@ -22,94 +18,10 @@ To compile run: ./configure make sudo make install # (if you want to install it into your system directories) - libiphone-initconf # (as the user you intend to user the library) On Ubuntu/Debian, you can do: sudo apt-get install build-essential automake autoconf \ - libgnutls-dev libusb-dev libfuse-dev libglib2.0-dev libxml2-dev \ - libreadline5-dev - -USAGE -================================================================================ - -Now comes the fun bit! - -== Generating keys == - -IMPORTANT: Before using the library you must run "libiphone-initconf" -as your own user (not root). It will generate keys and a host id for your -system to be able to communicate with 'lockdownd' on the iPhone. - -It will probably take 5-10 minutes, but thankfully only needs to be -run _once_. It MUST be run otherwise communication will not work: - - libiphone-initconf - -The generated keys are saved in '~/.config/libiphone/' in your home directory. - -== Tools == - -There are currently two more executables 'ifuse' and 'iphoneclient', -both located in src/. - - -=== iFuse === - -This is probably what you're after; this mounts a view of your -iPhone/iPod Touch's filesystem over the USB interface using the native -Apple protocol (AFC/"com.apple.afc"). - -ifuse is a Fuse filesystem which allows you to mount your iPhone to a directory -like this: - - ./src/ifuse -s - -To unmount: - umount - -(nb: '-s' is to force single-threaded mode, as ifuse maybe unstable without it). - -Eg: - mkdir ~/iphone - - ifuse ~/iphone -s - ls -l ~/iphone - ... - umount ~/iphone - -Currently ifuse (via the AFC protocol) only gives access to the -'/var/root/Media/' chroot on the iPhone (containing music/pictures). - -If you have a device that has been jailedbreaked then an additional -("com.apple.afc2") service will have been installed, without the chroot. -On jailbroken devices only, you can do: - - ifuse ~/iphone --root -s - -And this will mount a full view of the iPhone's filesystem. - - -==== Setting up FUSE ==== - -Note that on some systems, you may have to load the 'fuse' kernel -module first and to ensure that you are a member of the 'fuse' group: - - sudo modprobe fuse - sudo adduser $USER fuse - -You can check your membership of the 'fuse' group with: - - id | grep fuse && echo yes! || echo not yet... - -If you have just added yourself, you will need to logout and log back -in for the group change to become visible. - - -=== iphoneclient === - -'iphoneclient' is a basic commandline interface for testing, it just -runs a few various test operations such as attempting to view/create a -test file in the iPhone, but is mainly a developer tool. + libglib2.0-dev libxml2-dev == Who/what/where? == @@ -118,10 +30,10 @@ wiki: http://matt.colyer.name/projects/iphone-linux/index.php?title=Main_Page code: - git clone http://git.matt.colyer.name/2008/libiphone/ + git clone git://github.com/JonathanBeck/libplist.git mailing list: http://lists.mattcolyer.com/listinfo.cgi/iphone-linux-dev-mattcolyer.com updated: - 2008-09-02 + 2008-12-12 diff --git a/configure.ac b/configure.ac index 286b1d8..a665182 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT(libiphone, 0.1.0, nospam@nowhere.com) -AM_INIT_AUTOMAKE(libiphone, 0.1.0) +AC_INIT(libplist, 0.1.0, nospam@nowhere.com) +AM_INIT_AUTOMAKE(libplist, 0.1.0) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADER([config.h]) @@ -15,15 +15,11 @@ AM_PROG_CC_C_O # Checks for libraries. PKG_CHECK_MODULES(libxml2, libxml-2.0 >= 2.6.30) -PKG_CHECK_MODULES(libusb, libusb >= 0.1.12) PKG_CHECK_MODULES(libglib2, glib-2.0 >= 2.14.1) -PKG_CHECK_MODULES(libgthread2, gthread-2.0 >= 2.14.1) -PKG_CHECK_MODULES(libgnutls, gnutls >= 1.6.3 gnutls <= 2.5.0 ) -PKG_CHECK_MODULES(libtasn1, libtasn1 >= 1.1) # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h]) +AC_CHECK_HEADERS([stdint.h stdlib.h string.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -31,6 +27,7 @@ AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T +AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Checks for library functions. @@ -38,18 +35,6 @@ AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) -AC_ARG_ENABLE([dev-tools], - [AS_HELP_STRING([--enable-dev-tools], - [build development helper tools (default is no)])], - [build_dev_tools=true], - [build_dev_tools=false]) -if test "$build_dev_tools" = true; then - DEV_SUB=dev -else - DEV_SUB= -fi -AC_SUBST([DEV_SUB]) - AC_ARG_ENABLE([debug-code], [AS_HELP_STRING([--disable-debug-code], [disable debug message reporting in library (default is yes)])], @@ -59,4 +44,4 @@ if test "$no_debug_code" = true; then AC_DEFINE(STRIP_DEBUG_CODE,1,[Strip debug reporting code]) fi -AC_OUTPUT(Makefile src/Makefile include/Makefile fdi/Makefile dev/Makefile libiphone-1.0.pc) +AC_OUTPUT(Makefile src/Makefile include/Makefile libplist-1.0.pc) diff --git a/dev/Makefile.am b/dev/Makefile.am deleted file mode 100644 index 95b4d61..0000000 --- a/dev/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -INCLUDES = -I$(top_srcdir)/include - -AM_CFLAGS = $(libxml2_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) -g -AM_LDFLAGS = $(libxml2_LIBS) $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) - -bin_PROGRAMS = iphoneclient lckd-client afccheck plutil - -iphoneclient_SOURCES = main.c -iphoneclient_LDADD = ../src/libiphone.la - -lckd_client_SOURCES = lckdclient.c -lckd_client_CFLAGS = $(AM_CFLAGS) -lckd_client_LDFLAGS = -lreadline $(AM_LDFLAGS) -lckd_client_LDADD = ../src/libiphone.la - -afccheck_SOURCES = afccheck.c -afccheck_CFLAGS = $(AM_CFLAGS) -afccheck_LDFLAGS = $(AM_LDFLAGS) -afccheck_LDADD = ../src/libiphone.la - -plutil_SOURCES = plutil.c -plutil_CFLAGS = $(AM_CFLAGS) -plutil_LDFLAGS = $(AM_LDFLAGS) -plutil_LDADD = ../src/libiphone.la diff --git a/dev/afccheck.c b/dev/afccheck.c deleted file mode 100644 index 0ff420a..0000000 --- a/dev/afccheck.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * afccheck.c - * creates threads and check communication through AFC is done rigth - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include - -#include - -#define BUFFER_SIZE 20000 -#define NB_THREADS 10 - - -typedef struct { - iphone_afc_client_t afc; - int id; -} param; - - -void check_afc(gpointer data) -{ - //prepare a buffer - int buffersize = BUFFER_SIZE * sizeof(int); - int *buf = (int *) malloc(buffersize); - int *buf2 = (int *) malloc(buffersize); - int bytes = 0; - //fill buffer - int i = 0; - for (i = 0; i < BUFFER_SIZE; i++) { - buf[i] = ((param *) data)->id * i; - } - - //now writes buffer on iphone - iphone_afc_file_t file = NULL; - char path[50]; - sprintf(path, "/Buf%i", ((param *) data)->id); - iphone_afc_open_file(((param *) data)->afc, path, IPHONE_AFC_FILE_WRITE, &file); - iphone_afc_write_file(((param *) data)->afc, file, (char *) buf, buffersize, &bytes); - iphone_afc_close_file(((param *) data)->afc, file); - file = NULL; - if (bytes != buffersize) - printf("Write operation failed\n"); - - //now read it - bytes = 0; - iphone_afc_open_file(((param *) data)->afc, path, IPHONE_AFC_FILE_READ, &file); - iphone_afc_read_file(((param *) data)->afc, file, (char *) buf2, buffersize, &bytes); - iphone_afc_close_file(((param *) data)->afc, file); - if (bytes != buffersize) - printf("Read operation failed\n"); - - //compare buffers - for (i = 0; i < BUFFER_SIZE; i++) { - if (buf[i] != buf2[i]) { - printf("Buffers are differents, stream corrupted\n"); - break; - } - } - - //cleanup - iphone_afc_delete_file(((param *) data)->afc, path); - g_thread_exit(0); -} - -int main(int argc, char *argv[]) -{ - iphone_lckd_client_t control = NULL; - iphone_device_t phone = NULL; - GError *err; - int port = 0; - iphone_afc_client_t afc = NULL; - - if (IPHONE_E_SUCCESS != iphone_get_device(&phone)) { - printf("No iPhone found, is it plugged in?\n"); - return 1; - } - - if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) { - iphone_free_device(phone); - return 1; - } - - if (IPHONE_E_SUCCESS == iphone_lckd_start_service(control, "com.apple.afc", &port) && !port) { - iphone_lckd_free_client(control); - iphone_free_device(phone); - fprintf(stderr, "Something went wrong when starting AFC."); - return 1; - } - - iphone_afc_new_client(phone, 3432, port, &afc); - - //makes sure thread environment is available - if (!g_thread_supported()) - g_thread_init(NULL); - - GThread *threads[NB_THREADS]; - param data[NB_THREADS]; - - int i = 0; - for (i = 0; i < NB_THREADS; i++) { - data[i].afc = afc; - data[i].id = i + 1; - threads[i] = g_thread_create((GThreadFunc) check_afc, data + i, TRUE, &err); - } - - for (i = 0; i < NB_THREADS; i++) { - g_thread_join(threads[i]); - } - - - iphone_lckd_free_client(control); - iphone_free_device(phone); - - return 0; -} diff --git a/dev/lckdclient.c b/dev/lckdclient.c deleted file mode 100644 index c96f052..0000000 --- a/dev/lckdclient.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * lckdclient.c - * Rudimentary command line interface to the Lockdown protocol - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include - - -int main(int argc, char *argv[]) -{ - int bytes = 0, port = 0, i = 0; - iphone_lckd_client_t control = NULL; - iphone_device_t phone = NULL; - - iphone_set_debug(1); - - if (IPHONE_E_SUCCESS != iphone_get_device(&phone)) { - printf("No iPhone found, is it plugged in?\n"); - return -1; - } - - if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) { - iphone_free_device(phone); - return -1; - } - - char *uid = NULL; - if (IPHONE_E_SUCCESS == lockdownd_get_device_uid(control, &uid)) { - printf("DeviceUniqueID : %s\n", uid); - free(uid); - } - - using_history(); - int loop = TRUE; - while (loop) { - char *cmd = readline("> "); - if (cmd) { - - gchar **args = g_strsplit(cmd, " ", 0); - - int len = 0; - if (args) { - while (*(args + len)) { - g_strstrip(*(args + len)); - len++; - } - } - - if (len > 0) { - add_history(cmd); - if (!strcmp(*args, "quit")) - loop = FALSE; - - if (!strcmp(*args, "get") && len == 3) { - char *value = NULL; - if (IPHONE_E_SUCCESS == lockdownd_generic_get_value(control, *(args + 1), *(args + 2), &value)) - printf("Success : value = %s\n", value); - else - printf("Error\n"); - } - - if (!strcmp(*args, "start") && len == 2) { - int port = 0; - iphone_lckd_start_service(control, *(args + 1), &port); - printf("%i\n", port); - } - } - g_strfreev(args); - } - free(cmd); - cmd = NULL; - } - clear_history(); - iphone_lckd_free_client(control); - iphone_free_device(phone); - - return 0; -} diff --git a/dev/main.c b/dev/main.c deleted file mode 100644 index 4974eef..0000000 --- a/dev/main.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * main.c - * Rudimentary interface to the iPhone - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include - -#include -#include - -#include - - -int main(int argc, char *argv[]) -{ - int bytes = 0, port = 0, i = 0; - iphone_lckd_client_t control = NULL; - iphone_device_t phone = NULL; - - if (argc > 1 && !strcasecmp(argv[1], "--debug")) { - iphone_set_debug(1); - } else { - iphone_set_debug(0); - } - - if (IPHONE_E_SUCCESS != iphone_get_device(&phone)) { - printf("No iPhone found, is it plugged in?\n"); - return -1; - } - - if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) { - iphone_free_device(phone); - return -1; - } - - char *uid = NULL; - if (IPHONE_E_SUCCESS == lockdownd_get_device_uid(control, &uid)) { - printf("DeviceUniqueID : %s\n", uid); - free(uid); - } - - iphone_lckd_start_service(control, "com.apple.afc", &port); - - if (port) { - iphone_afc_client_t afc = NULL; - iphone_afc_new_client(phone, 3432, port, &afc); - if (afc) { - char **dirs = NULL; - iphone_afc_get_dir_list(afc, "/eafaedf", &dirs); - if (!dirs) - iphone_afc_get_dir_list(afc, "/", &dirs); - printf("Directory time.\n"); - for (i = 0; dirs[i]; i++) { - printf("/%s\n", dirs[i]); - } - - g_strfreev(dirs); - iphone_afc_get_devinfo(afc, &dirs); - if (dirs) { - for (i = 0; dirs[i]; i += 2) { - printf("%s: %s\n", dirs[i], dirs[i + 1]); - } - } - g_strfreev(dirs); - - iphone_afc_file_t my_file = NULL; - struct stat stbuf; - iphone_afc_get_file_attr(afc, "/iTunesOnTheGoPlaylist.plist", &stbuf); - if (IPHONE_E_SUCCESS == - iphone_afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", IPHONE_AFC_FILE_READ, &my_file) && my_file) { - printf("A file size: %i\n", (int) stbuf.st_size); - char *file_data = (char *) malloc(sizeof(char) * stbuf.st_size); - iphone_afc_read_file(afc, my_file, file_data, stbuf.st_size, &bytes); - if (bytes >= 0) { - printf("The file's data:\n"); - fwrite(file_data, 1, bytes, stdout); - } - printf("\nClosing my file.\n"); - iphone_afc_close_file(afc, my_file); - free(file_data); - } else - printf("couldn't open a file\n"); - - iphone_afc_open_file(afc, "/readme.libiphone.fx", IPHONE_AFC_FILE_WRITE, &my_file); - if (my_file) { - char *outdatafile = strdup("this is a bitchin text file\n"); - iphone_afc_write_file(afc, my_file, outdatafile, strlen(outdatafile), &bytes); - free(outdatafile); - if (bytes > 0) - printf("Wrote a surprise. ;)\n"); - else - printf("I wanted to write a surprise, but... :(\n"); - iphone_afc_close_file(afc, my_file); - } - printf("Deleting a file...\n"); - bytes = iphone_afc_delete_file(afc, "/delme"); - if (bytes) - printf("Success.\n"); - else - printf("Failure. (expected unless you have a /delme file on your phone)\n"); - - printf("Renaming a file...\n"); - bytes = iphone_afc_rename_file(afc, "/renme", "/renme2"); - if (bytes > 0) - printf("Success.\n"); - else - printf("Failure. (expected unless you have a /renme file on your phone)\n"); - - printf("Seek & read\n"); - iphone_afc_open_file(afc, "/readme.libiphone.fx", IPHONE_AFC_FILE_READ, &my_file); - if (IPHONE_E_SUCCESS != iphone_afc_seek_file(afc, my_file, 5)) - printf("WARN: SEEK DID NOT WORK\n"); - char *threeletterword = (char *) malloc(sizeof(char) * 5); - iphone_afc_read_file(afc, my_file, threeletterword, 3, &bytes); - threeletterword[3] = '\0'; - if (bytes > 0) - printf("Result: %s\n", threeletterword); - else - printf("Couldn't read!\n"); - free(threeletterword); - iphone_afc_close_file(afc, my_file); - - } - iphone_afc_free_client(afc); - } else { - printf("Start service failure.\n"); - } - - printf("All done.\n"); - - iphone_lckd_free_client(control); - iphone_free_device(phone); - - return 0; -} diff --git a/dev/plutil.c b/dev/plutil.c deleted file mode 100644 index 3d93797..0000000 --- a/dev/plutil.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * main.c for plistutil - * right now just prints debug shit - */ - -#include "../src/plist.h" -#include "plutil.h" -#include -#include -#include -#include - - -int main(int argc, char *argv[]) -{ - struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); - Options *options = parse_arguments(argc, argv); - - if (!options) { - print_usage(); - return 0; - } - - iphone_set_debug(options->debug); - - //read input file - FILE *iplist = fopen(options->in_file, "r"); - if (!iplist) - return 1; - stat(options->in_file, filestats); - char *plist_entire = (char *) malloc(sizeof(char) * (filestats->st_size + 1)); - fread(plist_entire, sizeof(char), filestats->st_size, iplist); - fclose(iplist); - - - //convert one format to another - plist_t root_node = NULL; - char *plist_out = NULL; - int size = 0; - - if (memcmp(plist_entire, "bplist00", 8) == 0) { - bin_to_plist(plist_entire, filestats->st_size, &root_node); - plist_to_xml(root_node, &plist_out, &size); - } else { - xml_to_plist(plist_entire, filestats->st_size, &root_node); - plist_to_bin(root_node, &plist_out, &size); - } - - if (plist_out) { - if (options->out_file != NULL) { - FILE *oplist = fopen(options->out_file, "wb"); - if (!oplist) - return 1; - fwrite(plist_out, size, sizeof(char), oplist); - fclose(oplist); - } - //if no output file specified, write to stdout - else - fwrite(plist_out, size, sizeof(char), stdout); - } else - printf("ERROR\n"); - return 0; -} - -Options *parse_arguments(int argc, char *argv[]) -{ - int i = 0; - - Options *options = (Options *) malloc(sizeof(Options)); - memset(options, 0, sizeof(Options)); - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--infile") || !strcmp(argv[i], "-i")) { - if ((i + 1) == argc) { - free(options); - return NULL; - } - options->in_file = argv[i + 1]; - i++; - continue; - } - - if (!strcmp(argv[i], "--outfile") || !strcmp(argv[i], "-o")) { - if ((i + 1) == argc) { - free(options); - return NULL; - } - options->out_file = argv[i + 1]; - i++; - continue; - } - - if (!strcmp(argv[i], "--debug") || !strcmp(argv[i], "-d") || !strcmp(argv[i], "-v")) { - options->debug = 1; - } - - if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { - free(options); - return NULL; - } - } - - if (!options->in_file /*|| !options->out_file */ ) { - free(options); - return NULL; - } - - return options; -} - -void print_usage() -{ - printf("Usage: plistutil -i|--infile in_file.plist -o|--outfile out_file.plist [--debug]\n"); - printf("\n"); - printf("\t-i or --infile: The file to read in.\n"); - printf("\t-o or --outfile: The file to convert to.\n"); - printf("\t-d, -v or --debug: Provide extended debug information.\n\n"); -} diff --git a/dev/plutil.h b/dev/plutil.h deleted file mode 100644 index 2146307..0000000 --- a/dev/plutil.h +++ /dev/null @@ -1,13 +0,0 @@ - -/* - * main.h - header for plistutil - * Written by FxChiP - */ - -typedef struct _options { - char *in_file, *out_file; - uint8_t debug, in_fmt, out_fmt; -} Options; - -Options *parse_arguments(int argc, char *argv[]); -void print_usage(); diff --git a/fdi/31-apple-mobile-device.fdi b/fdi/31-apple-mobile-device.fdi deleted file mode 100644 index 3e9ccc9..0000000 --- a/fdi/31-apple-mobile-device.fdi +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - afc - - - - - - - diff --git a/fdi/Makefile.am b/fdi/Makefile.am deleted file mode 100644 index 31e716b..0000000 --- a/fdi/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -freedesktopfdidir=$(prefix)/share/hal/fdi/information/20thirdparty/ -freedesktopfdi_DATA=31-apple-mobile-device.fdi - diff --git a/include/Makefile.am b/include/Makefile.am index a5f8766..4ed2784 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1 +1 @@ -nobase_include_HEADERS = libiphone/libiphone.h +nobase_include_HEADERS = plist/plist.h diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h deleted file mode 100644 index b3e3f95..0000000 --- a/include/libiphone/libiphone.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * libiphone.h - * Main include of libiphone - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBIPHONE_H -#define LIBIPHONE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -//general errors -#define IPHONE_E_SUCCESS 0 -#define IPHONE_E_INVALID_ARG -1 -#define IPHONE_E_UNKNOWN_ERROR -2 -#define IPHONE_E_NO_DEVICE -3 -#define IPHONE_E_TIMEOUT -4 -#define IPHONE_E_NOT_ENOUGH_DATA -5 -#define IPHONE_E_BAD_HEADER -6 - -//lockdownd specific error -#define IPHONE_E_INVALID_CONF -7 -#define IPHONE_E_PAIRING_FAILED -8 -#define IPHONE_E_SSL_ERROR -9 -#define IPHONE_E_PLIST_ERROR -10 -#define IPHONE_E_DICT_ERROR -11 - -//afc specific error -#define IPHONE_E_NO_SUCH_FILE -12 - -typedef int16_t iphone_error_t; - -typedef enum { - IPHONE_AFC_FILE_READ = 0x00000002, // seems to be able to read and write files - IPHONE_AFC_FILE_WRITE = 0x00000003, // writes and creates a file, blanks it out, etc. - IPHONE_AFC_FILE_RW = 0x00000005, // seems to do the same as 2. Might even create the file. - IPHONE_AFC_FILE_OP4 = 0x00000004, // no idea -- appears to be "write" -- clears file beforehand like 3 - IPHONE_AFC_FILE_OP6 = 0x00000006, // no idea yet -- appears to be the same as 5. - IPHONE_AFC_FILE_OP1 = 0x00000001, // no idea juuust yet... probably read. - IPHONE_AFC_FILE_OP0 = 0x00000000, - IPHONE_AFC_FILE_OP10 = 0x0000000a -} iphone_afc_file_mode_t; - -struct iphone_device_int; -typedef struct iphone_device_int *iphone_device_t; - -struct iphone_lckd_client_int; -typedef struct iphone_lckd_client_int *iphone_lckd_client_t; - -struct iphone_umux_client_int; -typedef struct iphone_umux_client_int *iphone_umux_client_t; - -struct iphone_afc_client_int; -typedef struct iphone_afc_client_int *iphone_afc_client_t; - -struct iphone_afc_file_int; -typedef struct iphone_afc_file_int *iphone_afc_file_t; - -//device related functions -void iphone_set_debug(int level); -iphone_error_t iphone_get_device ( iphone_device_t *device ); -iphone_error_t iphone_free_device ( iphone_device_t device ); - - -//lockdownd related functions -iphone_error_t iphone_lckd_new_client ( iphone_device_t device, iphone_lckd_client_t *client ); -iphone_error_t iphone_lckd_free_client( iphone_lckd_client_t client ); - -iphone_error_t iphone_lckd_start_service ( iphone_lckd_client_t client, const char *service, int *port ); -iphone_error_t iphone_lckd_recv ( iphone_lckd_client_t client, char **dump_data, uint32_t *recv_bytes ); -iphone_error_t iphone_lckd_send ( iphone_lckd_client_t client, char *raw_data, uint32_t length, uint32_t *recv_bytes ); - - -//usbmux related functions -iphone_error_t iphone_mux_new_client ( iphone_device_t device, uint16_t src_port, uint16_t dst_port, iphone_umux_client_t *client ); -iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client ); - -iphone_error_t iphone_mux_send ( iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t *sent_bytes ); -iphone_error_t iphone_mux_recv ( iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t *recv_bytes ); - - -//afc related functions -iphone_error_t iphone_afc_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_afc_client_t *client ); -iphone_error_t iphone_afc_free_client ( iphone_afc_client_t client ); - -iphone_error_t iphone_afc_get_devinfo ( iphone_afc_client_t client, char ***infos ); -iphone_error_t iphone_afc_get_dir_list ( iphone_afc_client_t client, const char *dir, char ***list); - -iphone_error_t iphone_afc_get_file_attr ( iphone_afc_client_t client, const char *filename, struct stat *stbuf ); -iphone_error_t iphone_afc_open_file ( iphone_afc_client_t client, const char *filename, iphone_afc_file_mode_t file_mode, iphone_afc_file_t *file ); -iphone_error_t iphone_afc_close_file ( iphone_afc_client_t client, iphone_afc_file_t file); -iphone_error_t iphone_afc_read_file ( iphone_afc_client_t client, iphone_afc_file_t file, char *data, int length, uint32_t *bytes); -iphone_error_t iphone_afc_write_file ( iphone_afc_client_t client, iphone_afc_file_t file, const char *data, int length, uint32_t *bytes); -iphone_error_t iphone_afc_seek_file ( iphone_afc_client_t client, iphone_afc_file_t file, int seekpos); -iphone_error_t iphone_afc_truncate_file ( iphone_afc_client_t client, iphone_afc_file_t file, uint32_t newsize); -iphone_error_t iphone_afc_delete_file ( iphone_afc_client_t client, const char *path); -iphone_error_t iphone_afc_rename_file ( iphone_afc_client_t client, const char *from, const char *to); -iphone_error_t iphone_afc_mkdir ( iphone_afc_client_t client, const char *dir); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/include/plist/plist.h b/include/plist/plist.h new file mode 100644 index 0000000..a67075c --- /dev/null +++ b/include/plist/plist.h @@ -0,0 +1,39 @@ +/* + * plist.h + * Main include of libplist + * + * Copyright (c) 2008 Jonathan Beck 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBPLIST_H +#define LIBPLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libiphone-1.0.pc.in b/libiphone-1.0.pc.in deleted file mode 100644 index c496464..0000000 --- a/libiphone-1.0.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libiphone -Description: A library to communicate with the Lockdown server on the iPhone -Version: @VERSION@ -Requires: libxml-2.0 >= 2.6.30 libusb >= 0.1.12 glib-2.0 >= 2.14.1 gthread-2.0 >= 2.14.1 gnutls >= 1.6.3 libtasn1 >= 1.1 -Libs: -L${libdir} -liphone -Cflags: -I${includedir} - diff --git a/libplist-1.0.pc.in b/libplist-1.0.pc.in new file mode 100644 index 0000000..34110e3 --- /dev/null +++ b/libplist-1.0.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libplist +Description: A library to handle Apple Property Lists whereas they are binary or XML +Version: @VERSION@ +Requires: libxml-2.0 >= 2.6.30 glib-2.0 >= 2.14.1 +Libs: -L${libdir} -lplist +Cflags: -I${includedir} + diff --git a/src/AFC.c b/src/AFC.c deleted file mode 100644 index 899bd47..0000000 --- a/src/AFC.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * AFC.c - * Contains functions for the built-in AFC client. - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "AFC.h" -#include "plist.h" - - -// This is the maximum size an AFC data packet can be -const int MAXIMUM_PACKET_SIZE = (2 << 15) - 32; - -/** Locks an AFC client, done for thread safety stuff - * - * @param client The AFC client connection to lock - */ -static void afc_lock(iphone_afc_client_t client) -{ - log_debug_msg("Locked\n"); - /*while (client->lock) { - usleep(500); // they say it's obsolete, but whatever - } - client->lock = 1; */ - g_mutex_lock(client->mutex); -} - -/** Unlocks an AFC client, done for thread safety stuff. - * - * @param client The AFC - */ -static void afc_unlock(iphone_afc_client_t client) -{ // just to be pretty - log_debug_msg("Unlocked\n"); - //client->lock = 0; - g_mutex_unlock(client->mutex); -} - -/** Makes a connection to the AFC service on the phone. - * - * @param phone The iPhone to connect on. - * @param s_port The source port. - * @param d_port The destination port. - * - * @return A handle to the newly-connected client or NULL upon error. - */ -iphone_error_t iphone_afc_new_client(iphone_device_t device, int src_port, int dst_port, iphone_afc_client_t * client) -{ - int ret = IPHONE_E_SUCCESS; - - //makes sure thread environment is available - if (!g_thread_supported()) - g_thread_init(NULL); - iphone_afc_client_t client_loc = (iphone_afc_client_t) malloc(sizeof(struct iphone_afc_client_int)); - - if (!device) - return IPHONE_E_INVALID_ARG; - - // Attempt connection - client_loc->connection = NULL; - ret = iphone_mux_new_client(device, src_port, dst_port, &client_loc->connection); - if (IPHONE_E_SUCCESS != ret || !client_loc->connection) { - free(client_loc); - return ret; - } - // Allocate a packet - client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); - if (!client_loc->afc_packet) { - iphone_mux_free_client(client_loc->connection); - free(client_loc); - return IPHONE_E_UNKNOWN_ERROR; - } - - client_loc->afc_packet->packet_num = 0; - client_loc->afc_packet->unknown1 = 0; - client_loc->afc_packet->unknown2 = 0; - client_loc->afc_packet->unknown3 = 0; - client_loc->afc_packet->unknown4 = 0; - client_loc->afc_packet->entire_length = 0; - client_loc->afc_packet->this_length = 0; - client_loc->afc_packet->header1 = 0x36414643; - client_loc->afc_packet->header2 = 0x4141504C; - client_loc->file_handle = 0; - client_loc->lock = 0; - client_loc->mutex = g_mutex_new(); - - *client = client_loc; - return IPHONE_E_SUCCESS; -} - -/** Disconnects an AFC client from the phone. - * - * @param client The client to disconnect. - */ -iphone_error_t iphone_afc_free_client(iphone_afc_client_t client) -{ - if (!client || !client->connection || !client->afc_packet) - return IPHONE_E_INVALID_ARG; - - iphone_mux_free_client(client->connection); - free(client->afc_packet); - free(client); - return IPHONE_E_SUCCESS; -} - - -/** Dispatches an AFC packet over a client. - * - * @param client The client to send data through. - * @param data The data to send. - * @param length The length to send. - * - * @return The number of bytes actually sent, or -1 on error. - * - * @warning set client->afc_packet->this_length and - * client->afc_packet->entire_length to 0 before calling this. The - * reason is that if you set them to different values, it indicates - * you want to send the data as two packets. - */ -static int dispatch_AFC_packet(iphone_afc_client_t client, const char *data, int length) -{ - int bytes = 0, offset = 0; - char *buffer; - - if (!client || !client->connection || !client->afc_packet) - return 0; - if (!data || !length) - length = 0; - - client->afc_packet->packet_num++; - if (!client->afc_packet->entire_length) { - client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket); - client->afc_packet->this_length = client->afc_packet->entire_length; - } - if (!client->afc_packet->this_length) { - client->afc_packet->this_length = sizeof(AFCPacket); - } - // We want to send two segments; buffer+sizeof(AFCPacket) to - // this_length is the parameters - // And everything beyond that is the next packet. (for writing) - if (client->afc_packet->this_length != client->afc_packet->entire_length) { - buffer = (char *) malloc(client->afc_packet->this_length); - memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket)); - offset = client->afc_packet->this_length - sizeof(AFCPacket); - - log_debug_msg("dispatch_AFC_packet: Offset: %i\n", offset); - if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { - log_debug_msg("dispatch_AFC_packet: Length did not resemble what it was supposed"); - log_debug_msg("to based on the packet.\n"); - log_debug_msg("length minus offset: %i\n", length - offset); - log_debug_msg("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length); - free(buffer); - return -1; - } - memcpy(buffer + sizeof(AFCPacket), data, offset); - iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, &bytes); - free(buffer); - if (bytes <= 0) { - return bytes; - } - - log_debug_msg("dispatch_AFC_packet: sent the first now go with the second\n"); - log_debug_msg("Length: %i\n", length - offset); - log_debug_msg("Buffer: \n"); - log_debug_msg(data + offset); - - iphone_mux_send(client->connection, data + offset, length - offset, &bytes); - return bytes; - } else { - log_debug_msg("dispatch_AFC_packet doin things the old way\n"); - char *buffer = (char *) malloc(sizeof(char) * client->afc_packet->this_length); - log_debug_msg("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); - memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket)); - log_debug_msg("dispatch_AFC_packet packet data follows\n"); - if (length > 0) { - memcpy(buffer + sizeof(AFCPacket), data, length); - buffer[sizeof(AFCPacket) + length] = '\0'; - } - log_debug_buffer(buffer, client->afc_packet->this_length); - log_debug_msg("\n"); - iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, &bytes); - - if (buffer) { - free(buffer); - buffer = NULL; - } - return bytes; - } - return -1; -} - -/** Receives data through an AFC client and sets a variable to the received data. - * - * @param client The client to receive data on. - * @param dump_here The char* to point to the newly-received data. - * - * @return How much data was received, 0 on successful receive with no errors, - * -1 if there was an error involved with receiving or if the packet - * received raised a non-trivial error condition (i.e. non-zero with - * AFC_ERROR operation) - */ - -static int receive_AFC_data(iphone_afc_client_t client, char **dump_here) -{ - AFCPacket *r_packet; - char *buffer = (char *) malloc(sizeof(AFCPacket) * 4); - char *final_buffer = NULL; - int bytes = 0, recv_len = 0, current_count = 0; - int retval = 0; - - iphone_mux_recv(client->connection, buffer, sizeof(AFCPacket) * 4, &bytes); - if (bytes <= 0) { - free(buffer); - fprintf(stderr, "Just didn't get enough.\n"); - *dump_here = NULL; - return -1; - } - - r_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); - memcpy(r_packet, buffer, sizeof(AFCPacket)); - - if (r_packet->entire_length == r_packet->this_length - && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) { - *dump_here = (char *) malloc(sizeof(char) * (r_packet->entire_length - sizeof(AFCPacket))); - memcpy(*dump_here, buffer + sizeof(AFCPacket), r_packet->entire_length - sizeof(AFCPacket)); - retval = r_packet->entire_length - sizeof(AFCPacket); - free(buffer); - free(r_packet); - return retval; - } - - uint32_t param1 = buffer[sizeof(AFCPacket)]; - free(buffer); - - if (r_packet->operation == AFC_ERROR && !(client->afc_packet->operation == AFC_DELETE && param1 == 7)) { - log_debug_msg("Oops? Bad operation code received: 0x%X, operation=0x%X, param1=%d\n", - r_packet->operation, client->afc_packet->operation, param1); - recv_len = r_packet->entire_length - r_packet->this_length; - free(r_packet); - log_debug_msg("recv_len=%d\n", recv_len); - if (param1 == 0) { - log_debug_msg("... false alarm, but still\n"); - *dump_here = NULL; - return 0; - } else { - log_debug_msg("Errno %i\n", param1); - } - *dump_here = NULL; - return -1; - } else { - log_debug_msg("Operation code %x\nFull length %i and this length %i\n", - r_packet->operation, r_packet->entire_length, r_packet->this_length); - } - - recv_len = r_packet->entire_length - r_packet->this_length; - free(r_packet); - if (!recv_len && r_packet->operation == AFC_SUCCESS_RESPONSE) { - *dump_here = NULL; - return 0; - } - // Keep collecting packets until we have received the entire file. - buffer = (char *) malloc(sizeof(char) * (recv_len < MAXIMUM_PACKET_SIZE) ? recv_len : MAXIMUM_PACKET_SIZE); - final_buffer = (char *) malloc(sizeof(char) * recv_len); - while (current_count < recv_len) { - iphone_mux_recv(client->connection, buffer, recv_len - current_count, &bytes); - log_debug_msg("receive_AFC_data: still collecting packets\n"); - if (bytes < 0) { - log_debug_msg("receive_AFC_data: mux_recv failed: %d\n", bytes); - break; - } - if (bytes > recv_len - current_count) { - log_debug_msg("receive_AFC_data: mux_recv delivered too much data\n"); - break; - } - if (bytes > 7 && strstr(buffer, "CFA6LPAA")) { - log_debug_msg("receive_AFC_data: WARNING: there is AFC data in this packet at %ti\n", - strstr(buffer, "CFA6LPAA") - buffer); - log_debug_msg("receive_AFC_data: the total packet length is %i\n", bytes); - } - - memcpy(final_buffer + current_count, buffer, bytes); - current_count += bytes; - } - free(buffer); - - *dump_here = final_buffer; - return current_count; -} - -static int count_nullspaces(char *string, int number) -{ - int i = 0, nulls = 0; - - for (i = 0; i < number; i++) { - if (string[i] == '\0') - nulls++; - } - - return nulls; -} - -static char **make_strings_list(char *tokens, int true_length) -{ - int nulls = 0, i = 0, j = 0; - char **list = NULL; - - if (!tokens || !true_length) - return NULL; - - nulls = count_nullspaces(tokens, true_length); - list = (char **) malloc(sizeof(char *) * (nulls + 1)); - for (i = 0; i < nulls; i++) { - list[i] = strdup(tokens + j); - j += strlen(list[i]) + 1; - } - list[i] = NULL; - - return list; -} - -/** Gets a directory listing of the directory requested. - * - * @param client The client to get a directory listing from. - * @param dir The directory to list. (must be a fully-qualified path) - * - * @return A char ** list of files in that directory, terminated by an empty - * string for now or NULL if there was an error. - */ -iphone_error_t iphone_afc_get_dir_list(iphone_afc_client_t client, const char *dir, char ***list) -{ - int bytes = 0; - char *data = NULL, **list_loc = NULL; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - if (!client || !dir || !list || (list && *list)) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send the command - client->afc_packet->operation = AFC_LIST_DIR; - client->afc_packet->entire_length = 0; - client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, dir, strlen(dir)); - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive the data - bytes = receive_AFC_data(client, &data); - if (bytes < 0 && !data) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Parse the data - list_loc = make_strings_list(data, bytes); - if (list_loc) - ret = IPHONE_E_SUCCESS; - if (data) - free(data); - - afc_unlock(client); - *list = list_loc; - - return ret; -} - -/** Get device info for a client connection to phone. (free space on disk, etc.) - * - * @param client The client to get device info for. - * - * @return A char ** list of parameters as given by AFC or NULL if there was an - * error. - */ -iphone_error_t iphone_afc_get_devinfo(iphone_afc_client_t client, char ***infos) -{ - int bytes = 0; - char *data = NULL, **list = NULL; - - if (!client || !infos) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send the command - client->afc_packet->operation = AFC_GET_DEVINFO; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, NULL, 0); - if (bytes < 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive the data - bytes = receive_AFC_data(client, &data); - if (bytes < 0 && !data) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Parse the data - list = make_strings_list(data, bytes); - if (data) - free(data); - - afc_unlock(client); - *infos = list; - return IPHONE_E_SUCCESS; -} - -/** Deletes a file. - * - * @param client The client to have delete the file. - * @param path The file to delete. (must be a fully-qualified path) - * - * @return IPHONE_E_SUCCESS if everythong went well, IPHONE_E_INVALID_ARG - * if arguments are NULL or invalid, IPHONE_E_NOT_ENOUGH_DATA otherwise. - */ -iphone_error_t iphone_afc_delete_file(iphone_afc_client_t client, const char *path) -{ - char *response = NULL; - int bytes; - - if (!client || !path || !client->afc_packet || !client->connection) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send command - client->afc_packet->this_length = client->afc_packet->entire_length = 0; - client->afc_packet->operation = AFC_DELETE; - bytes = dispatch_AFC_packet(client, path, strlen(path)); - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive response - bytes = receive_AFC_data(client, &response); - if (response) - free(response); - - afc_unlock(client); - - if (bytes < 0) { - return IPHONE_E_NOT_ENOUGH_DATA; - } else { - return IPHONE_E_SUCCESS; - } -} - -/** Renames a file on the phone. - * - * @param client The client to have rename the file. - * @param from The file to rename. (must be a fully-qualified path) - * @param to The new name of the file. (must also be a fully-qualified path) - * - * @return IPHONE_E_SUCCESS if everythong went well, IPHONE_E_INVALID_ARG - * if arguments are NULL or invalid, IPHONE_E_NOT_ENOUGH_DATA otherwise. - */ -iphone_error_t iphone_afc_rename_file(iphone_afc_client_t client, const char *from, const char *to) -{ - char *response = NULL; - char *send = (char *) malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32_t))); - int bytes = 0; - - if (!client || !from || !to || !client->afc_packet || !client->connection) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send command - memcpy(send, from, strlen(from) + 1); - memcpy(send + strlen(from) + 1, to, strlen(to) + 1); - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - client->afc_packet->operation = AFC_RENAME; - bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2); - free(send); - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive response - bytes = receive_AFC_data(client, &response); - if (response) - free(response); - - afc_unlock(client); - - if (bytes < 0) { - return IPHONE_E_NOT_ENOUGH_DATA; - } else { - return IPHONE_E_SUCCESS; - } -} - -/** Creates a directory on the phone. - * - * @param client The client to use to make a directory. - * @param dir The directory's path. (must be a fully-qualified path, I assume - * all other mkdir restrictions apply as well) - * - * @return IPHONE_E_SUCCESS if everythong went well, IPHONE_E_INVALID_ARG - * if arguments are NULL or invalid, IPHONE_E_NOT_ENOUGH_DATA otherwise. - */ -iphone_error_t iphone_afc_mkdir(iphone_afc_client_t client, const char *dir) -{ - int bytes = 0; - char *response = NULL; - - if (!client) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send command - client->afc_packet->operation = AFC_MAKE_DIR; - client->afc_packet->this_length = client->afc_packet->entire_length = 0; - bytes = dispatch_AFC_packet(client, dir, strlen(dir)); - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive response - bytes = receive_AFC_data(client, &response); - if (response) - free(response); - - afc_unlock(client); - - if (bytes < 0) { - return IPHONE_E_NOT_ENOUGH_DATA; - } else { - return IPHONE_E_SUCCESS; - } -} - -/** Gets information about a specific file. - * - * @param client The client to use to get the information of the file. - * @param path The fully-qualified path to the file. - * - * @return A pointer to an AFCFile struct containing the information received, - * or NULL on failure. - */ -iphone_afc_file_t afc_get_file_info(iphone_afc_client_t client, const char *path) -{ - char *received, **list; - iphone_afc_file_t my_file; - int length, i = 0; - - afc_lock(client); - - // Send command - client->afc_packet->operation = AFC_GET_INFO; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - dispatch_AFC_packet(client, path, strlen(path)); - - // Receive data - length = receive_AFC_data(client, &received); - if (received) { - list = make_strings_list(received, length); - free(received); - } else { - afc_unlock(client); - return NULL; - } - - afc_unlock(client); - - // Parse the data - if (list) { - my_file = (iphone_afc_file_t) malloc(sizeof(struct iphone_afc_file_int)); - for (i = 0; list[i]; i++) { - if (!strcmp(list[i], "st_size")) { - my_file->size = atoi(list[i + 1]); - } - - if (!strcmp(list[i], "st_blocks")) { - my_file->blocks = atoi(list[i + 1]); - } - - if (!strcmp(list[i], "st_ifmt")) { - if (!strcmp(list[i + 1], "S_IFREG")) { - my_file->type = S_IFREG; - } else if (!strcmp(list[i + 1], "S_IFDIR")) { - my_file->type = S_IFDIR; - } - } - } - g_strfreev(list); - return my_file; - } else { - return NULL; - } -} - -/** Gets information about a specific file. - * - * @param client The client to use to get the information of the file. - * @param path The fully-qualified path to the file - * @param stbuf output buffer where file information will be stored - * - * @return A pointer to an AFCFile struct containing the information received, - * or NULL on failure. - */ -iphone_error_t iphone_afc_get_file_attr(iphone_afc_client_t client, const char *filename, struct stat * stbuf) -{ - - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - if (!client || !client->connection || !client->afc_packet || !stbuf) - return IPHONE_E_INVALID_ARG; - - memset(stbuf, 0, sizeof(struct stat)); - iphone_afc_file_t file = afc_get_file_info(client, filename); - if (!file) { - ret = IPHONE_E_NO_SUCH_FILE; - } else { - stbuf->st_mode = file->type | (S_ISDIR(file->type) ? 0755 : 0644); - stbuf->st_size = file->size; - stbuf->st_blksize = 2048; // FIXME: Is this the actual block - // size used on the iPhone? - stbuf->st_blocks = file->blocks; - stbuf->st_uid = getuid(); - stbuf->st_gid = getgid(); - - ret = iphone_afc_close_file(client, file); - } - return ret; -} - -/** Opens a file on the phone. - * - * @param client The client to use to open the file. - * @param filename The file to open. (must be a fully-qualified path) - * @param file_mode The mode to use to open the file. Can be AFC_FILE_READ or - * AFC_FILE_WRITE; the former lets you read and write, - * however, and the second one will *create* the file, - * destroying anything previously there. - * - * @return A pointer to an AFCFile struct containing the file information (as - * received by afc_get_file_info) as well as the handle to the file or - * NULL in the case of failure. - */ -iphone_error_t -iphone_afc_open_file(iphone_afc_client_t client, const char *filename, - iphone_afc_file_mode_t file_mode, iphone_afc_file_t * file) -{ - iphone_afc_file_t file_loc = NULL; - uint32_t ag = 0; - int bytes = 0, length = 0; - char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1)); - - if (!client || !client->connection || !client->afc_packet) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - // Send command - memcpy(data, &file_mode, 4); - memcpy(data + 4, &ag, 4); - memcpy(data + 8, filename, strlen(filename)); - data[8 + strlen(filename)] = '\0'; - client->afc_packet->operation = AFC_FILE_OPEN; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, data, 8 + strlen(filename)); - free(data); - - if (bytes <= 0) { - log_debug_msg("afc_open_file: Didn't receive a response to the command\n"); - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive the data - length = receive_AFC_data(client, &data); - if (length > 0 && data) { - afc_unlock(client); - - // Get the file info and return it - file_loc = afc_get_file_info(client, filename); - memcpy(&file_loc->filehandle, data, 4); - free(data); - *file = file_loc; - return IPHONE_E_SUCCESS; - } else { - log_debug_msg("afc_open_file: Didn't get any further data\n"); - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - - afc_unlock(client); - - return IPHONE_E_UNKNOWN_ERROR; -} - -/** Attempts to the read the given number of bytes from the given file. - * - * @param client The relevant AFC client - * @param file The AFCFile to read from - * @param data The pointer to the memory region to store the read data - * @param length The number of bytes to read - * - * @return The number of bytes read if successful. If there was an error -1. - */ -iphone_error_t -iphone_afc_read_file(iphone_afc_client_t client, iphone_afc_file_t file, char *data, int length, uint32_t * bytes) -{ - char *input = NULL; - int current_count = 0, bytes_loc = 0; - const int MAXIMUM_READ_SIZE = 1 << 16; - - if (!client || !client->afc_packet || !client->connection || !file) - return IPHONE_E_INVALID_ARG; - log_debug_msg("afc_read_file called for length %i\n", length); - - afc_lock(client); - - // Looping here to get around the maximum amount of data that - // recieve_AFC_data can handle - while (current_count < length) { - log_debug_msg("afc_read_file: current count is %i but length is %i\n", current_count, length); - - // Send the read command - AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); - packet->unknown1 = packet->unknown2 = 0; - packet->filehandle = file->filehandle; - packet->size = ((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE; - client->afc_packet->operation = AFC_READ; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes_loc = dispatch_AFC_packet(client, (char *) packet, sizeof(AFCFilePacket)); - free(packet); - - if (bytes_loc <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive the data - bytes_loc = receive_AFC_data(client, &input); - log_debug_msg("afc_read_file: bytes returned: %i\n", bytes_loc); - if (bytes_loc < 0) { - if (input) - free(input); - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } else if (bytes_loc == 0) { - if (input) - free(input); - afc_unlock(client); - *bytes = current_count; - return IPHONE_E_SUCCESS; // FIXME check that's actually a - // success - } else { - if (input) { - log_debug_msg("afc_read_file: %d\n", bytes_loc); - memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); - free(input); - input = NULL; - current_count += (bytes_loc > length) ? length : bytes_loc; - } - } - } - log_debug_msg("afc_read_file: returning current_count as %i\n", current_count); - - afc_unlock(client); - *bytes = current_count; - return IPHONE_E_SUCCESS; -} - -/** Writes a given number of bytes to a file. - * - * @param client The client to use to write to the file. - * @param file A pointer to an AFCFile struct; serves as the file handle. - * @param data The data to write to the file. - * @param length How much data to write. - * - * @return The number of bytes written to the file, or a value less than 0 if - * none were written... - */ -iphone_error_t -iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, - const char *data, int length, uint32_t * bytes) -{ - char *acknowledgement = NULL; - const int MAXIMUM_WRITE_SIZE = 1 << 15; - uint32_t zero = 0, bytes_loc = 0, segments = (length / MAXIMUM_WRITE_SIZE), current_count = 0, i = 0; - char *out_buffer = NULL; - - if (!client || !client->afc_packet || !client->connection || !file || !bytes) - return IPHONE_E_INVALID_ARG; - - afc_lock(client); - - log_debug_msg("afc_write_file: Write length: %i\n", length); - - // Divide the file into segments. - for (i = 0; i < segments; i++) { - // Send the segment - client->afc_packet->this_length = sizeof(AFCPacket) + 8; - client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE; - client->afc_packet->operation = AFC_WRITE; - out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); - memcpy(out_buffer, (char *) &file->filehandle, sizeof(uint32_t)); - memcpy(out_buffer + 4, (char *) &zero, sizeof(uint32_t)); - memcpy(out_buffer + 8, data + current_count, MAXIMUM_WRITE_SIZE); - bytes_loc = dispatch_AFC_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8); - if (bytes_loc < 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - free(out_buffer); - out_buffer = NULL; - - current_count += bytes_loc; - bytes_loc = receive_AFC_data(client, &acknowledgement); - if (bytes_loc < 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - } - - // By this point, we should be at the end. i.e. the last segment that - // didn't get sent in the for loop - // this length is fine because it's always sizeof(AFCPacket) + 8, but - // to be sure we do it again - if (current_count == length) { - afc_unlock(client); - *bytes = current_count; - return IPHONE_E_SUCCESS; - } - - client->afc_packet->this_length = sizeof(AFCPacket) + 8; - client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count); - client->afc_packet->operation = AFC_WRITE; - out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); - memcpy(out_buffer, (char *) &file->filehandle, sizeof(uint32_t)); - memcpy(out_buffer + 4, (char *) &zero, sizeof(uint32_t)); - memcpy(out_buffer + 8, data + current_count, (length - current_count)); - bytes_loc = dispatch_AFC_packet(client, out_buffer, (length - current_count) + 8); - free(out_buffer); - out_buffer = NULL; - - current_count += bytes_loc; - - if (bytes_loc <= 0) { - afc_unlock(client); - *bytes = current_count; - return IPHONE_E_SUCCESS; - } - - zero = bytes_loc; - bytes_loc = receive_AFC_data(client, &acknowledgement); - afc_unlock(client); - if (bytes_loc < 0) { - log_debug_msg("afc_write_file: uh oh?\n"); - } - *bytes = current_count; - return IPHONE_E_SUCCESS; -} - -/** Closes a file on the phone. - * - * @param client The client to close the file with. - * @param file A pointer to an AFCFile struct containing the file handle of the - * file to close. - */ -iphone_error_t iphone_afc_close_file(iphone_afc_client_t client, iphone_afc_file_t file) -{ - if (!client || !file) - return IPHONE_E_INVALID_ARG; - char *buffer = malloc(sizeof(char) * 8); - uint32_t zero = 0; - int bytes = 0; - - afc_lock(client); - - log_debug_msg("afc_close_file: File handle %i\n", file->filehandle); - - // Send command - memcpy(buffer, &file->filehandle, sizeof(uint32_t)); - memcpy(buffer + sizeof(uint32_t), &zero, sizeof(zero)); - client->afc_packet->operation = AFC_FILE_CLOSE; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8); - free(buffer); - buffer = NULL; - - // FIXME: Is this necesary? - // client->afc_packet->entire_length = client->afc_packet->this_length - // = 0; - - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_UNKNOWN_ERROR; - } - // Receive the response - bytes = receive_AFC_data(client, &buffer); - if (buffer) - free(buffer); - free(file); - afc_unlock(client); - return IPHONE_E_SUCCESS; -} - -/** Seeks to a given position of a pre-opened file on the phone. - * - * @param client The client to use to seek to the position. - * @param file The file to seek to a position on. - * @param seekpos Where to seek to. If passed a negative value, this will seek - * from the end of the file. - * - * @return IPHONE_E_SUCCESS on success, IPHONE_E_NOT_ENOUGH_DATA on failure. - */ -iphone_error_t iphone_afc_seek_file(iphone_afc_client_t client, iphone_afc_file_t file, int seekpos) -{ - char *buffer = (char *) malloc(sizeof(char) * 24); - uint32_t seekto = 0, bytes = 0, zero = 0; - - if (seekpos < 0) - seekpos = file->size - abs(seekpos); - - afc_lock(client); - - // Send the command - seekto = seekpos; - memcpy(buffer, &file->filehandle, sizeof(uint32_t)); // handle - memcpy(buffer + 4, &zero, sizeof(uint32_t)); // pad - memcpy(buffer + 8, &zero, sizeof(uint32_t)); // fromwhere - memcpy(buffer + 12, &zero, sizeof(uint32_t)); // pad - memcpy(buffer + 16, &seekto, sizeof(uint32_t)); // offset - memcpy(buffer + 20, &zero, sizeof(uint32_t)); // pad - client->afc_packet->operation = AFC_FILE_SEEK; - client->afc_packet->this_length = client->afc_packet->entire_length = 0; - bytes = dispatch_AFC_packet(client, buffer, 23); - free(buffer); - buffer = NULL; - - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive response - bytes = receive_AFC_data(client, &buffer); - if (buffer) - free(buffer); - - afc_unlock(client); - - if (bytes >= 0) { - return IPHONE_E_SUCCESS; - } else { - return IPHONE_E_NOT_ENOUGH_DATA; - } -} - -/** Sets the size of a file on the phone. - * - * @param client The client to use to set the file size. - * @param file The (pre-opened) file to set the size on. - * @param newsize The size to set the file to. - * - * @return 0 on success, -1 on failure. - * - * @note This function is more akin to ftruncate than truncate, and truncate - * calls would have to open the file before calling this, sadly. - */ -iphone_error_t iphone_afc_truncate_file(iphone_afc_client_t client, iphone_afc_file_t file, uint32_t newsize) -{ - char *buffer = (char *) malloc(sizeof(char) * 16); - uint32_t bytes = 0, zero = 0; - - afc_lock(client); - - // Send command - memcpy(buffer, &file->filehandle, sizeof(uint32_t)); // handle - memcpy(buffer + 4, &zero, sizeof(uint32_t)); // pad - memcpy(buffer + 8, &newsize, sizeof(uint32_t)); // newsize - memcpy(buffer + 12, &zero, 3); // pad - client->afc_packet->operation = AFC_FILE_TRUNCATE; - client->afc_packet->this_length = client->afc_packet->entire_length = 0; - bytes = dispatch_AFC_packet(client, buffer, 15); - free(buffer); - buffer = NULL; - - if (bytes <= 0) { - afc_unlock(client); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Receive response - bytes = receive_AFC_data(client, &buffer); - if (buffer) - free(buffer); - - afc_unlock(client); - - if (bytes >= 0) { - return IPHONE_E_SUCCESS; - } else { - return IPHONE_E_NOT_ENOUGH_DATA; - } -} - -uint32_t iphone_afc_get_file_handle(iphone_afc_file_t file) -{ - return file->filehandle; -} diff --git a/src/AFC.h b/src/AFC.h deleted file mode 100644 index 5e4d17c..0000000 --- a/src/AFC.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * AFC.h - * Defines and structs and the like for the built-in AFC client - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "usbmux.h" -#include "iphone.h" - -#include -#include -#include -#include -#include - -typedef struct { - uint32_t header1, header2; - uint32_t entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; -} AFCPacket; - -typedef struct { - uint32_t filehandle, unknown1, size, unknown2; -} AFCFilePacket; - -typedef struct __AFCToken { - struct __AFCToken *last, *next; - char *token; -} AFCToken; - -struct iphone_afc_client_int { - iphone_umux_client_t connection; - AFCPacket *afc_packet; - int file_handle; - int lock; - GMutex *mutex; -}; - -struct iphone_afc_file_int { - uint32_t filehandle, blocks, size, type; -}; - - - -enum { - AFC_ERROR = 0x00000001, - AFC_GET_INFO = 0x0000000a, - AFC_GET_DEVINFO = 0x0000000b, - AFC_LIST_DIR = 0x00000003, - AFC_MAKE_DIR = 0x00000009, - AFC_DELETE = 0x00000008, - AFC_RENAME = 0x00000018, - AFC_SUCCESS_RESPONSE = 0x00000002, - AFC_FILE_OPEN = 0x0000000d, - AFC_FILE_CLOSE = 0x00000014, - AFC_FILE_SEEK = 0x00000011, - AFC_FILE_TRUNCATE = 0x00000015, - AFC_FILE_HANDLE = 0x0000000e, - AFC_READ = 0x0000000f, - AFC_WRITE = 0x00000010 -}; - -uint32_t iphone_afc_get_file_handle(iphone_afc_file_t file); diff --git a/src/Makefile.am b/src/Makefile.am index 82fd924..1b81710 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,15 +1,7 @@ INCLUDES = -I$(top_srcdir)/include -AM_CFLAGS = $(libxml2_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) -g -AM_LDFLAGS = $(libxml2_LIBS) $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) +AM_CFLAGS = $(libxml2_CFLAGS) $(libglib2_CFLAGS) +AM_LDFLAGS = $(libxml2_LIBS) $(libglib2_LIBS) -bin_PROGRAMS = libiphone-initconf - - -libiphone_initconf_SOURCES = initconf.c userpref.c utils.c -libiphone_initconf_CFLAGS = $(libgthread2_CFLAGS) $(AM_CFLAGS) -libiphone_initconf_LDFLAGS = $(libgthread2_LIBS) $(AM_LDFLAGS) - - -lib_LTLIBRARIES = libiphone.la -libiphone_la_SOURCES = usbmux.c iphone.c plist.c bplist.c xplist.c lockdown.c AFC.c userpref.c utils.c +lib_LTLIBRARIES = libplist.la +libplist_la_SOURCES = plist.c bplist.c xplist.c utils.c diff --git a/src/initconf.c b/src/initconf.c deleted file mode 100644 index 00d78e2..0000000 --- a/src/initconf.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * userpref.c - * contains methods to access user specific certificates IDs and more. - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include "libiphone/libiphone.h" -#include "userpref.h" -#include "utils.h" - -/** Generates a 2048 byte key, split into a function so that it can be run in a - * thread. - * - * @param key The pointer to the desired location of the new key. - */ -void generate_key(gpointer key) -{ - gnutls_x509_privkey_generate(*((gnutls_x509_privkey_t *) key), GNUTLS_PK_RSA, 2048, 0); - g_thread_exit(0); -} - -/** Simple function that generates a spinner until the mutex is released. - */ -void progress_bar(gpointer mutex) -{ - const char *spinner = "|/-\\|/-\\"; - int i = 0; - - while (!g_static_mutex_trylock((GStaticMutex *) mutex)) { - usleep(500000); - printf("Generating key... %c\r", spinner[i++]); - fflush(stdout); - if (i > 8) - i = 0; - } - printf("Generating key... done\n"); - g_thread_exit(0); -} - -int get_rand(int min, int max) -{ - int retval = (rand() % (max - min)) + min; - return retval; -} - -/** Generates a valid HostID (which is actually a UUID). - * - * @param A null terminated string containing a valid HostID. - */ -char *lockdownd_generate_hostid() -{ - char *hostid = (char *) malloc(sizeof(char) * 37); // HostID's are just UUID's, and UUID's are 36 characters long - const char *chars = "ABCDEF0123456789"; - srand(time(NULL)); - int i = 0; - - for (i = 0; i < 36; i++) { - if (i == 8 || i == 13 || i == 18 || i == 23) { - hostid[i] = '-'; - continue; - } else { - hostid[i] = chars[get_rand(0, 16)]; - } - } - hostid[36] = '\0'; // make it a real string - return hostid; -} - -int main(int argc, char *argv[]) -{ - GThread *progress_thread, *key_thread; - GError *err; - static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - char *host_id = NULL; - gnutls_x509_privkey_t root_privkey; - gnutls_x509_privkey_t host_privkey; - gnutls_x509_crt_t root_cert; - gnutls_x509_crt_t host_cert; - - iphone_set_debug(1); - - // Create the thread - if (!g_thread_supported()) { - g_thread_init(NULL); - } - gnutls_global_init(); - - printf("This program generates keys required to connect with the iPhone\n"); - printf("It only needs to be run ONCE.\n\n"); - printf("Additionally it may take several minutes to run, please be patient.\n\n"); - - - gnutls_x509_privkey_init(&root_privkey); - gnutls_x509_privkey_init(&host_privkey); - - gnutls_x509_crt_init(&root_cert); - gnutls_x509_crt_init(&host_cert); - - /* generate HostID */ - host_id = lockdownd_generate_hostid(); - - /* generate root key */ - g_static_mutex_lock(&mutex); - if ((key_thread = g_thread_create((GThreadFunc) generate_key, &root_privkey, TRUE, &err)) == NULL) { - printf("Thread create failed: %s!!\n", err->message); - g_error_free(err); - } - if ((progress_thread = g_thread_create((GThreadFunc) progress_bar, &mutex, TRUE, &err)) == NULL) { - printf("Thread create failed: %s!!\n", err->message); - g_error_free(err); - } - g_thread_join(key_thread); - g_static_mutex_unlock(&mutex); - g_thread_join(progress_thread); - - /* generate host key */ - g_static_mutex_init(&mutex); - g_static_mutex_lock(&mutex); - if ((key_thread = g_thread_create((GThreadFunc) generate_key, &host_privkey, TRUE, &err)) == NULL) { - printf("Thread create failed: %s!!\n", err->message); - g_error_free(err); - } - if ((progress_thread = g_thread_create((GThreadFunc) progress_bar, &mutex, TRUE, &err)) == NULL) { - printf("Thread create failed: %s!!\n", err->message); - g_error_free(err); - } - g_thread_join(key_thread); - g_static_mutex_unlock(&mutex); - g_thread_join(progress_thread); - - /* generate certificates */ - gnutls_x509_crt_set_key(root_cert, root_privkey); - gnutls_x509_crt_set_serial(root_cert, "\x00", 1); - gnutls_x509_crt_set_version(root_cert, 3); - gnutls_x509_crt_set_ca_status(root_cert, 1); - gnutls_x509_crt_set_activation_time(root_cert, time(NULL)); - gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - gnutls_x509_crt_sign(root_cert, root_cert, root_privkey); - - - gnutls_x509_crt_set_key(host_cert, host_privkey); - gnutls_x509_crt_set_serial(host_cert, "\x00", 1); - gnutls_x509_crt_set_version(host_cert, 3); - gnutls_x509_crt_set_ca_status(host_cert, 0); - gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE); - gnutls_x509_crt_set_activation_time(host_cert, time(NULL)); - gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - gnutls_x509_crt_sign(host_cert, root_cert, root_privkey); - - - /* export to PEM format */ - gnutls_datum_t root_key_pem = { NULL, 0 }; - gnutls_datum_t host_key_pem = { NULL, 0 }; - - gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_pem.size); - gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_pem.size); - - root_key_pem.data = gnutls_malloc(root_key_pem.size); - host_key_pem.data = gnutls_malloc(host_key_pem.size); - - gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, root_key_pem.data, &root_key_pem.size); - gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, host_key_pem.data, &host_key_pem.size); - - gnutls_datum_t root_cert_pem = { NULL, 0 }; - gnutls_datum_t host_cert_pem = { NULL, 0 }; - - gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_pem.size); - gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_pem.size); - - root_cert_pem.data = gnutls_malloc(root_cert_pem.size); - host_cert_pem.data = gnutls_malloc(host_cert_pem.size); - - printf("Generating root certificate..."); - gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_pem.size); - printf("done\n"); - - printf("Generating host certificate..."); - gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_pem.size); - printf("done\n"); - - - /* store values in config file */ - init_config_file(host_id, &root_key_pem, &host_key_pem, &root_cert_pem, &host_cert_pem); - - gnutls_free(root_key_pem.data); - gnutls_free(host_key_pem.data); - gnutls_free(root_cert_pem.data); - gnutls_free(host_cert_pem.data); - - return 0; -} diff --git a/src/iphone.c b/src/iphone.c deleted file mode 100644 index b7f6cc4..0000000 --- a/src/iphone.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * iphone.c - * Functions for creating and initializing iPhone structures. - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "usbmux.h" -#include "iphone.h" -#include "utils.h" -#include -#include -#include -#include -#include - - -/** - * Given a USB bus and device number, returns a device handle to the iPhone on - * that bus. To aid compatibility with future devices, this function does not - * check the vendor and device IDs! To do that, you should use - * iphone_get_device() or a system-specific API (e.g. HAL). - * - * @param bus_n The USB bus number. - * @param dev_n The USB device number. - * @param device A pointer to a iphone_device_t, which must be set to NULL upon - * calling iphone_get_specific_device, which will be filled with a device - * descriptor on return. - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. - */ -iphone_error_t iphone_get_specific_device(int bus_n, int dev_n, iphone_device_t * device) -{ - struct usb_bus *bus, *busses; - struct usb_device *dev; - usbmux_version_header *version; - int bytes = 0; - - //check we can actually write in device - if (!device || (device && *device)) - return IPHONE_E_INVALID_ARG; - - iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int)); - - // Initialize the struct - phone->device = NULL; - phone->__device = NULL; - phone->buffer = NULL; - - // Initialize libusb - usb_init(); - usb_find_busses(); - usb_find_devices(); - busses = usb_get_busses(); - - // Set the device configuration - for (bus = busses; bus; bus = bus->next) - if (bus->location == bus_n) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->devnum == dev_n) { - phone->__device = dev; - phone->device = usb_open(phone->__device); - usb_set_configuration(phone->device, 3); - usb_claim_interface(phone->device, 1); - goto found; - } - - iphone_free_device(phone); - - log_debug_msg("iphone_get_specific_device: iPhone not found\n"); - return IPHONE_E_NO_DEVICE; - - found: - // Send the version command to the phone - version = version_header(); - bytes = usb_bulk_write(phone->device, BULKOUT, (char *) version, sizeof(*version), 800); - if (bytes < 20) { - log_debug_msg("get_iPhone(): libusb did NOT send enough!\n"); - if (bytes < 0) { - log_debug_msg("get_iPhone(): libusb gave me the error %d: %s (%s)\n", - bytes, usb_strerror(), strerror(-bytes)); - } - } - // Read the phone's response - bytes = usb_bulk_read(phone->device, BULKIN, (char *) version, sizeof(*version), 800); - - // Check for bad response - if (bytes < 20) { - free(version); - iphone_free_device(phone); - log_debug_msg("get_iPhone(): Invalid version message -- header too short.\n"); - if (bytes < 0) - log_debug_msg("get_iPhone(): libusb error message %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes)); - return IPHONE_E_NOT_ENOUGH_DATA; - } - // Check for correct version - if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { - // We're all ready to roll. - fprintf(stderr, "get_iPhone() success\n"); - free(version); - *device = phone; - return IPHONE_E_SUCCESS; - } else { - // Bad header - iphone_free_device(phone); - free(version); - log_debug_msg("get_iPhone(): Received a bad header/invalid version number."); - return IPHONE_E_BAD_HEADER; - } - - // If it got to this point it's gotta be bad - log_debug_msg("get_iPhone(): Unknown error.\n"); - iphone_free_device(phone); - free(version); - return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad -} - -/** - * Scans all USB busses and devices for a known AFC-compatible device and - * returns a handle to the first such device it finds. Known devices include - * those with vendor ID 0x05ac and product ID between 0x1290 and 0x1293 - * inclusive. - * - * This function is convenient, but on systems where higher-level abstractions - * (such as HAL) are available it may be preferable to use - * iphone_get_specific_device instead, because it can deal with multiple - * connected devices as well as devices not known to libiphone. - * - * @param device Upon calling this function, a pointer to a location of type - * iphone_device_t, which must have the value NULL. On return, this location - * will be filled with a handle to the device. - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. - */ -iphone_error_t iphone_get_device(iphone_device_t * device) -{ - struct usb_bus *bus, *busses; - struct usb_device *dev; - - usb_init(); - usb_find_busses(); - usb_find_devices(); - - for (bus = usb_get_busses(); bus != NULL; bus = bus->next) - for (dev = bus->devices; dev != NULL; dev = dev->next) - if (dev->descriptor.idVendor == 0x05ac - && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293) - return iphone_get_specific_device(bus->location, dev->devnum, device); - - return IPHONE_E_NO_DEVICE; -} - -/** Cleans up an iPhone structure, then frees the structure itself. - * This is a library-level function; deals directly with the iPhone to tear - * down relations, but otherwise is mostly internal. - * - * @param phone A pointer to an iPhone structure. - */ -iphone_error_t iphone_free_device(iphone_device_t device) -{ - if (!device) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - if (device->buffer) { - free(device->buffer); - } - if (device->device) { - usb_release_interface(device->device, 1); - usb_reset(device->device); - usb_close(device->device); - ret = IPHONE_E_SUCCESS; - } - free(device); - return ret; -} - -/** Sends data to the phone - * This is a low-level (i.e. directly to phone) function. - * - * @param phone The iPhone to send data to - * @param data The data to send to the iPhone - * @param datalen The length of the data - * @return The number of bytes sent, or -1 on error or something. - */ -int send_to_phone(iphone_device_t phone, char *data, int datalen) -{ - if (!phone) - return -1; - int bytes = 0; - - if (!phone) - return -1; - log_debug_msg("send_to_phone: Attempting to send datalen = %i data = %p\n", datalen, data); - - bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, 800); - if (bytes < datalen) { - if (bytes < 0) - log_debug_msg("send_to_iphone(): libusb gave me the error %d: %s - %s\n", bytes, usb_strerror(), - strerror(-bytes)); - return -1; - } else { - return bytes; - } - - return -1; -} - -/** This function is a low-level (i.e. direct to iPhone) function. - * - * @param phone The iPhone to receive data from - * @param data Where to put data read - * @param datalen How much data to read in - * - * @return How many bytes were read in, or -1 on error. - */ -int recv_from_phone(iphone_device_t phone, char *data, int datalen) -{ - if (!phone) - return -1; - int bytes = 0; - - if (!phone) - return -1; - log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); - - bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); - if (bytes < 0) { - log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), - strerror(-bytes)); - return -1; - } - - return bytes; -} diff --git a/src/iphone.h b/src/iphone.h deleted file mode 100644 index 222a1be..0000000 --- a/src/iphone.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * iphone.h - * iPhone struct - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef IPHONE_H -#define IPHONE_H - -#ifndef USBMUX_H -#include "usbmux.h" -#warning usbmux not included? -#endif - -#include -#include - -#define BULKIN 0x85 -#define BULKOUT 0x04 - -struct iphone_device_int { - char *buffer; - struct usb_dev_handle *device; - struct usb_device *__device; -}; - -// Function definitions -int send_to_phone(iphone_device_t phone, char *data, int datalen); -int recv_from_phone(iphone_device_t phone, char *data, int datalen); -#endif diff --git a/src/lockdown.c b/src/lockdown.c deleted file mode 100644 index e882128..0000000 --- a/src/lockdown.c +++ /dev/null @@ -1,969 +0,0 @@ -/* - * lockdown.c - * libiphone built-in lockdownd client - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "usbmux.h" -#include "iphone.h" -#include "lockdown.h" -#include "userpref.h" -#include -#include -#include -#include -#include -#include - -const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { - {"PKCS1", 536872976, 0}, - {0, 1073741836, 0}, - {"RSAPublicKey", 536870917, 0}, - {"modulus", 1073741827, 0}, - {"publicExponent", 3, 0}, - {0, 0, 0} -}; - - - -/** Creates a lockdownd client for the give iPhone. - * - * @param phone The iPhone to create a lockdownd client for - * - * @return The lockdownd client. - */ -iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone) -{ - if (!phone) - return NULL; - iphone_lckd_client_t control = (iphone_lckd_client_t) malloc(sizeof(struct iphone_lckd_client_int)); - - if (IPHONE_E_SUCCESS != iphone_mux_new_client(phone, 0x0a00, 0xf27e, &control->connection)) { - free(control); - return NULL; - } - - control->ssl_session = (gnutls_session_t *) malloc(sizeof(gnutls_session_t)); - control->in_SSL = 0; - control->gtls_buffer_hack_len = 0; - return control; -} - -/** Closes the lockdownd client and does the necessary housekeeping. - * - * @param control The lockdown client - */ -iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client) -{ - if (!client) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - if (client->connection) { - ret = iphone_mux_free_client(client->connection); - } - - if (client->ssl_session) - gnutls_deinit(*client->ssl_session); - free(client->ssl_session); - free(client); - return ret; -} - -/** Polls the iPhone for lockdownd data. - * - * @param control The lockdownd client - * @param dump_data The pointer to the location of the buffer in which to store - * the received data - * - * @return The number of bytes received - */ -iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, uint32_t * recv_bytes) -{ - if (!client || !dump_data || !recv_bytes) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - char *receive; - uint32_t datalen = 0, bytes = 0; - - if (!client->in_SSL) - ret = iphone_mux_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); - else { - bytes = gnutls_record_recv(*client->ssl_session, &datalen, sizeof(datalen)); - if (bytes > 0) - ret = IPHONE_E_SUCCESS; - } - datalen = ntohl(datalen); - - receive = (char *) malloc(sizeof(char) * datalen); - if (!client->in_SSL) - ret = iphone_mux_recv(client->connection, receive, datalen, &bytes); - else { - bytes = gnutls_record_recv(*client->ssl_session, receive, datalen); - if (bytes > 0) - ret = IPHONE_E_SUCCESS; - } - *dump_data = receive; - *recv_bytes = bytes; - return ret; -} - -/** Sends lockdownd data to the iPhone - * - * @note This function is low-level and should only be used if you need to send - * a new type of message. - * - * @param control The lockdownd client - * @param raw_data The null terminated string buffer to send - * @param length The length of data to send - * - * @return The number of bytes sent - */ -iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes) -{ - if (!client || !raw_data || length == 0 || !sent_bytes) - return IPHONE_E_INVALID_ARG; - char *real_query; - int bytes; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - real_query = (char *) malloc(sizeof(char) * (length + 4)); - length = htonl(length); - memcpy(real_query, &length, sizeof(length)); - memcpy(real_query + 4, raw_data, ntohl(length)); - log_debug_msg("lockdownd_send(): made the query, sending it along\n"); - dump_debug_buffer("grpkt", real_query, ntohl(length) + 4); - - if (!client->in_SSL) - ret = iphone_mux_send(client->connection, real_query, ntohl(length) + sizeof(length), &bytes); - else { - gnutls_record_send(*client->ssl_session, real_query, ntohl(length) + sizeof(length)); - ret = IPHONE_E_SUCCESS; - } - log_debug_msg("lockdownd_send(): sent it!\n"); - free(real_query); - *sent_bytes = bytes; - return ret; -} - -/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. - * - * @note You most likely want lockdownd_init unless you are doing something special. - * - * @param control The lockdownd client - * - * @return 1 on success and 0 on failure. - */ -iphone_error_t lockdownd_hello(iphone_lckd_client_t control) -{ - if (!control) - return IPHONE_E_INVALID_ARG; - - int bytes = 0, i = 0; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - plist_t dict = NULL; - plist_new_dict(&dict); - - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType", strlen("QueryType")); - - log_debug_msg("lockdownd_hello() called\n"); - char *XML_content = NULL; - uint32_t length = 0; - - plist_to_xml(dict, &XML_content, &length); - log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); - XML_content = NULL; - plist_free(dict); - dict = NULL; - - ret = iphone_lckd_recv(control, &XML_content, &bytes); - log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content); - xml_to_plist(XML_content, bytes, &dict); - - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = find_query_node(dict, "Request", "QueryType"); - plist_t result_node = g_node_next_sibling(query_node); - plist_t value_node = g_node_next_sibling(result_node); - - plist_type result_type; - plist_type value_type; - - char *result_value = NULL; - char *value_value = NULL; - uint64_t result_length = 0; - uint64_t value_length = 0; - - get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length); - get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length); - - if (result_type == PLIST_KEY && - value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { - log_debug_msg("lockdownd_hello(): success\n"); - ret = IPHONE_E_SUCCESS; - } - - return ret; -} - -/** Generic function to handle simple (key, value) requests. - * - * @param control an initialized lockdownd client. - * @param key the key to request - * @param value a pointer to the requested value - * - * @return IPHONE_E_SUCCESS on success. - */ -iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *req_key, char *req_string, - gnutls_datum_t * value) -{ - if (!control || !req_key || !value || value->data) - return IPHONE_E_INVALID_ARG; - - plist_t dict = NULL; - int bytes = 0, i = 0; - char *XML_content = NULL; - uint32_t length = 0; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - /* Setup DevicePublicKey request plist */ - plist_new_dict(&dict); - plist_add_dict_element(dict, req_key, PLIST_STRING, (void *) req_string, strlen(req_string)); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "GetValue", strlen("GetValue")); - plist_to_xml(dict, &XML_content, &length); - - /* send to iPhone */ - log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); - XML_content = NULL; - plist_free(dict); - dict = NULL; - - if (ret != IPHONE_E_SUCCESS) - return ret; - - /* Now get iPhone's answer */ - ret = iphone_lckd_recv(control, &XML_content, &bytes); - log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content); - - if (ret != IPHONE_E_SUCCESS) - return ret; - - xml_to_plist(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = find_query_node(dict, "Request", "GetValue"); - plist_t result_key_node = g_node_next_sibling(query_node); - plist_t result_value_node = g_node_next_sibling(result_key_node); - - plist_type result_key_type; - plist_type result_value_type; - char *result_key = NULL; - char *result_value = NULL; - uint64_t result_length = 0; - uint64_t value_length = 0; - - get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &result_length); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &value_length); - - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { - log_debug_msg("lockdownd_generic_get_value(): success\n"); - ret = IPHONE_E_SUCCESS; - } - - if (ret != IPHONE_E_SUCCESS) { - return IPHONE_E_DICT_ERROR; - } - - plist_t value_key_node = g_node_next_sibling(result_key_node); - plist_t value_value_node = g_node_next_sibling(value_key_node); - plist_type value_key_type; - plist_type value_value_type; - char *value_key = NULL; - char *value_value = NULL; - uint64_t key_length = 0; - uint64_t valval_length = 0; - - get_type_and_value(value_key_node, &value_key_type, (void *) (&value_key), &key_length); - get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value), &valval_length); - - if (value_key_type == PLIST_KEY && !strcmp(result_key, "Value")) { - log_debug_msg("lockdownd_generic_get_value(): success\n"); - value->data = value_value; - value->size = valval_length; - ret = IPHONE_E_SUCCESS; - } - - plist_free(dict); - free(XML_content); - return ret; -} - -/** Askes for the device's unique id. Part of the lockdownd handshake. - * - * @note You most likely want lockdownd_init unless you are doing something special. - * - * @return 1 on success and 0 on failure. - */ -iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid) -{ - gnutls_datum_t temp = { NULL, 0 }; - return lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", &temp); - *uid = temp.data; -} - -/** Askes for the device's public key. Part of the lockdownd handshake. - * - * @note You most likely want lockdownd_init unless you are doing something special. - * - * @return 1 on success and 0 on failure. - */ -iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key) -{ - return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key); -} - -/** Completes the entire lockdownd handshake. - * - * @param phone The iPhone - * @param lockdownd_client The pointer to the location of the lockdownd_client - * - * @return 1 on success and 0 on failure - */ -iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client_t * client) -{ - if (!device || !client || (client && *client)) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_SUCCESS; - char *host_id = NULL; - - iphone_lckd_client_t client_loc = new_lockdownd_client(device); - if (IPHONE_E_SUCCESS != lockdownd_hello(client_loc)) { - fprintf(stderr, "Hello failed in the lockdownd client.\n"); - ret = IPHONE_E_NOT_ENOUGH_DATA; - } - - - char *uid = NULL; - ret = lockdownd_get_device_uid(client_loc, &uid); - if (IPHONE_E_SUCCESS != ret) { - fprintf(stderr, "Device refused to send uid.\n"); - } - - host_id = get_host_id(); - if (IPHONE_E_SUCCESS == ret && !host_id) { - fprintf(stderr, "No HostID found, run libiphone-initconf.\n"); - ret = IPHONE_E_INVALID_CONF; - } - - if (IPHONE_E_SUCCESS == ret && !is_device_known(uid)) - ret = lockdownd_pair_device(client_loc, uid, host_id); - - if (uid) { - free(uid); - uid = NULL; - } - - ret = lockdownd_start_SSL_session(client_loc, host_id); - if (IPHONE_E_SUCCESS != ret) { - ret = IPHONE_E_SSL_ERROR; - fprintf(stderr, "SSL Session opening failed.\n"); - } - - if (host_id) { - free(host_id); - host_id = NULL; - } - - if (IPHONE_E_SUCCESS == ret) - *client = client_loc; - return ret; -} - -/** Generates the appropriate keys and pairs the device. It's part of the - * lockdownd handshake. - * - * @note You most likely want lockdownd_init unless you are doing something special. - * - * @return 1 on success and 0 on failure - */ -iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, char *host_id) -{ - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - plist_t dict = NULL; - plist_t dict_record = NULL; - int bytes = 0, i = 0; - char *XML_content = NULL; - uint32_t length = 0; - - gnutls_datum_t device_cert = { NULL, 0 }; - gnutls_datum_t host_cert = { NULL, 0 }; - gnutls_datum_t root_cert = { NULL, 0 }; - gnutls_datum_t public_key = { NULL, 0 }; - - ret = lockdownd_get_device_public_key(control, &public_key); - if (ret != IPHONE_E_SUCCESS) { - fprintf(stderr, "Device refused to send public key.\n"); - return ret; - } - - ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); - if (ret != IPHONE_E_SUCCESS) { - free(public_key.data); - return ret; - } - - /* Setup Pair request plist */ - plist_new_dict(&dict); - plist_add_dict_element(dict, "PairRecord", PLIST_DICT, NULL, 0); - dict_record = g_node_last_child(dict); - plist_add_dict_element(dict_record, "DeviceCertificate", PLIST_DATA, (void *) device_cert.data, device_cert.size); - plist_add_dict_element(dict_record, "HostCertificate", PLIST_DATA, (void *) host_cert.data, host_cert.size); - plist_add_dict_element(dict_record, "HostID", PLIST_STRING, (void *) host_id, strlen(host_id)); - plist_add_dict_element(dict_record, "RootCertificate", PLIST_DATA, (void *) root_cert.data, root_cert.size); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "Pair", strlen("Pair")); - plist_to_xml(dict, &XML_content, &length); - log_debug_msg("XML Pairing request :\nsize : %i\nxml :\n %s", length, XML_content); - - /* send to iPhone */ - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); - plist_free(dict); - dict = NULL; - - if (ret != IPHONE_E_SUCCESS) - return ret; - - /* Now get iPhone's answer */ - ret = iphone_lckd_recv(control, &XML_content, &bytes); - - if (ret != IPHONE_E_SUCCESS) - return ret; - - log_debug_msg("lockdown_pair_device: iPhone's response to our pair request:\n"); - log_debug_msg(XML_content); - log_debug_msg("\n\n"); - - xml_to_plist(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = find_query_node(dict, "Request", "Pair"); - plist_t result_key_node = g_node_next_sibling(query_node); - plist_t result_value_node = g_node_next_sibling(result_key_node); - - plist_type result_key_type; - plist_type result_value_type; - char *result_key = NULL; - char *result_value = NULL; - uint64_t key_length = 0; - uint64_t val_length = 0; - - get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length); - - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { - ret = IPHONE_E_SUCCESS; - } - - /* store public key in config if pairing succeeded */ - if (ret == IPHONE_E_SUCCESS) { - log_debug_msg("lockdownd_pair_device: pair success\n"); - store_device_public_key(uid, public_key); - ret = IPHONE_E_SUCCESS; - } else { - log_debug_msg("lockdownd_pair_device: pair failure\n"); - ret = IPHONE_E_PAIRING_FAILED; - } - free(public_key.data); - return ret; -} - -/** Generates the device certificate from the public key as well as the host - * and root certificates. - * - * @return IPHONE_E_SUCCESS on success. - */ -iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * odevice_cert, - gnutls_datum_t * ohost_cert, gnutls_datum_t * oroot_cert) -{ - if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert) - return IPHONE_E_INVALID_ARG; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - gnutls_datum_t modulus = { NULL, 0 }; - gnutls_datum_t exponent = { NULL, 0 }; - - /* now decode the PEM encoded key */ - gnutls_datum_t der_pub_key; - if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) { - - /* initalize asn.1 parser */ - ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY; - if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) { - - ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY; - asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key); - - if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) { - - /* get size to read */ - int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, &modulus.size); - int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, &exponent.size); - - modulus.data = gnutls_malloc(modulus.size); - exponent.data = gnutls_malloc(exponent.size); - - ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, &modulus.size); - ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, &exponent.size); - if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2) - ret = IPHONE_E_SUCCESS; - } - if (asn1_pub_key) - asn1_delete_structure(&asn1_pub_key); - } - if (pkcs1) - asn1_delete_structure(&pkcs1); - } - - /* now generate certifcates */ - if (IPHONE_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { - - gnutls_global_init(); - gnutls_datum_t essentially_null = { strdup("abababababababab"), strlen("abababababababab") }; - - gnutls_x509_privkey_t fake_privkey, root_privkey; - gnutls_x509_crt_t dev_cert, root_cert, host_cert; - - gnutls_x509_privkey_init(&fake_privkey); - gnutls_x509_crt_init(&dev_cert); - gnutls_x509_crt_init(&root_cert); - gnutls_x509_crt_init(&host_cert); - - if (GNUTLS_E_SUCCESS == - gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, - &essentially_null, &essentially_null)) { - - gnutls_x509_privkey_init(&root_privkey); - - /* get root cert */ - gnutls_datum_t pem_root_cert = { NULL, 0 }; - get_root_certificate(&pem_root_cert); - if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(root_cert, &pem_root_cert, GNUTLS_X509_FMT_PEM)) - ret = IPHONE_E_SSL_ERROR; - - /* get host cert */ - gnutls_datum_t pem_host_cert = { NULL, 0 }; - get_host_certificate(&pem_host_cert); - if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(host_cert, &pem_host_cert, GNUTLS_X509_FMT_PEM)) - ret = IPHONE_E_SSL_ERROR; - - /* get root private key */ - gnutls_datum_t pem_root_priv = { NULL, 0 }; - get_root_private_key(&pem_root_priv); - if (GNUTLS_E_SUCCESS != gnutls_x509_privkey_import(root_privkey, &pem_root_priv, GNUTLS_X509_FMT_PEM)) - ret = IPHONE_E_SSL_ERROR; - - /* generate device certificate */ - gnutls_x509_crt_set_key(dev_cert, fake_privkey); - gnutls_x509_crt_set_serial(dev_cert, "\x00", 1); - gnutls_x509_crt_set_version(dev_cert, 3); - gnutls_x509_crt_set_ca_status(dev_cert, 0); - gnutls_x509_crt_set_activation_time(dev_cert, time(NULL)); - gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey); - - if (IPHONE_E_SUCCESS == ret) { - /* if everything went well, export in PEM format */ - gnutls_datum_t dev_pem = { NULL, 0 }; - gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &dev_pem.size); - dev_pem.data = gnutls_malloc(dev_pem.size); - gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size); - - /* copy buffer for output */ - odevice_cert->data = malloc(dev_pem.size); - memcpy(odevice_cert->data, dev_pem.data, dev_pem.size); - odevice_cert->size = dev_pem.size; - - ohost_cert->data = malloc(pem_host_cert.size); - memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size); - ohost_cert->size = pem_host_cert.size; - - oroot_cert->data = malloc(pem_root_cert.size); - memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size); - oroot_cert->size = pem_root_cert.size; - } - gnutls_free(pem_root_priv.data); - gnutls_free(pem_root_cert.data); - gnutls_free(pem_host_cert.data); - } - } - - gnutls_free(modulus.data); - gnutls_free(exponent.data); - - gnutls_free(der_pub_key.data); - - return ret; -} - -/** Starts SSL communication with lockdownd after the iPhone has been paired. - * - * @param control The lockdownd client - * @param HostID The HostID used with this phone - * - * @return 1 on success and 0 on failure - */ -iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const char *HostID) -{ - plist_t dict = NULL; - char *XML_content = NULL; - uint32_t length = 0, bytes = 0, return_me = 0; - - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - /* Setup DevicePublicKey request plist */ - plist_new_dict(&dict); - plist_add_dict_element(dict, "HostID", PLIST_STRING, (void *) HostID, strlen(HostID)); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartSession", strlen("StartSession")); - plist_to_xml(dict, &XML_content, &length); - log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); - XML_content = NULL; - plist_free(dict); - dict = NULL; - - if (ret != IPHONE_E_SUCCESS) - return ret; - - if (bytes > 0) { - ret = iphone_lckd_recv(control, &XML_content, &bytes); - log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content); - xml_to_plist(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = find_query_node(dict, "Request", "StartSession"); - plist_t result_key_node = g_node_next_sibling(query_node); - plist_t result_value_node = g_node_next_sibling(result_key_node); - - plist_type result_key_type; - plist_type result_value_type; - char *result_key = NULL; - char *result_value = NULL; - uint64_t key_length = 0; - uint64_t val_length = 0; - - get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length); - - free(XML_content); - XML_content = NULL; - plist_free(dict); - dict = NULL; - - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { - // Set up GnuTLS... - //gnutls_anon_client_credentials_t anoncred; - gnutls_certificate_credentials_t xcred; - - log_debug_msg("We started the session OK, now trying GnuTLS\n"); - errno = 0; - gnutls_global_init(); - //gnutls_anon_allocate_client_credentials(&anoncred); - gnutls_certificate_allocate_credentials(&xcred); - gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM); - gnutls_init(control->ssl_session, GNUTLS_CLIENT); - { - int protocol_priority[16] = { GNUTLS_SSL3, 0 }; - int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; - int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; - int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; - int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; - - gnutls_cipher_set_priority(*control->ssl_session, cipher_priority); - gnutls_compression_set_priority(*control->ssl_session, comp_priority); - gnutls_kx_set_priority(*control->ssl_session, kx_priority); - gnutls_protocol_set_priority(*control->ssl_session, protocol_priority); - gnutls_mac_set_priority(*control->ssl_session, mac_priority); - - } - gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me. - - log_debug_msg("GnuTLS step 1...\n"); - gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control); - log_debug_msg("GnuTLS step 2...\n"); - gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func) & lockdownd_secuwrite); - log_debug_msg("GnuTLS step 3...\n"); - gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func) & lockdownd_securead); - log_debug_msg("GnuTLS step 4 -- now handshaking...\n"); - - if (errno) - log_debug_msg("WARN: errno says %s before handshake!\n", strerror(errno)); - return_me = gnutls_handshake(*control->ssl_session); - log_debug_msg("GnuTLS handshake done...\n"); - - if (return_me != GNUTLS_E_SUCCESS) { - log_debug_msg("GnuTLS reported something wrong.\n"); - gnutls_perror(return_me); - log_debug_msg("oh.. errno says %s\n", strerror(errno)); - return IPHONE_E_SSL_ERROR; - } else { - control->in_SSL = 1; - return IPHONE_E_SUCCESS; - } - } - - log_debug_msg("Apparently failed negotiating with lockdownd.\n"); - log_debug_msg("Responding dictionary: \n"); - return IPHONE_E_SSL_ERROR; - } else { - log_debug_msg("Didn't get enough bytes.\n"); - return IPHONE_E_NOT_ENOUGH_DATA; - } -} - -/** gnutls callback for writing data to the iPhone. - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The data to send - * @param length The length of data to send in bytes - * - * @return The number of bytes sent - */ -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ - int bytes = 0; - iphone_lckd_client_t control; - control = (iphone_lckd_client_t) transport; - log_debug_msg("lockdownd_secuwrite() called\n"); - log_debug_msg("pre-send\nlength = %zi\n", length); - iphone_mux_send(control->connection, buffer, length, &bytes); - log_debug_msg("post-send\nsent %i bytes\n", bytes); - - dump_debug_buffer("sslpacketwrite.out", buffer, length); - return bytes; -} - -/** gnutls callback for reading data from the iPhone - * - * @param transport It's really the lockdownd client, but the method signature has to match - * @param buffer The buffer to store data in - * @param length The length of data to read in bytes - * - * @return The number of bytes read - */ -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) -{ - int bytes = 0, pos_start_fill = 0; - char *hackhackhack = NULL; - iphone_lckd_client_t control; - control = (iphone_lckd_client_t) transport; - log_debug_msg("lockdownd_securead() called\nlength = %zi\n", length); - // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more. - if (control->gtls_buffer_hack_len > 0) { - if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got - length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length - pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at - memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially - free(control->gtls_buffer_hack); // free our memory, it's not chained anymore - control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore - log_debug_msg("Did a partial fill to help quench thirst for data\n"); - } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less... - control->gtls_buffer_hack_len -= length; // subtract what they're asking for - memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer - hackhackhack = (char *) malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer. - memcpy(hackhackhack, control->gtls_buffer_hack + length, control->gtls_buffer_hack_len); // Move what's left into the new one - free(control->gtls_buffer_hack); // Free the old one - control->gtls_buffer_hack = hackhackhack; // And make it the new one. - hackhackhack = NULL; - log_debug_msg("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len); - return length; // hand it over. - } else { // length == hack length - memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs - free(control->gtls_buffer_hack); // free our "obligation" - control->gtls_buffer_hack_len = 0; // free our "obligation" - log_debug_msg("Satiated the thirst for data; now we have to eventually receive again.\n"); - return length; // hand it over - } - } - // End buffering hack! - char *recv_buffer = (char *) malloc(sizeof(char) * (length * 1000)); // ensuring nothing stupid happens - - log_debug_msg("pre-read\nclient wants %zi bytes\n", length); - iphone_mux_recv(control->connection, recv_buffer, (length * 1000), &bytes); - log_debug_msg("post-read\nwe got %i bytes\n", bytes); - if (bytes < 0) { - log_debug_msg("lockdownd_securead(): uh oh\n"); - log_debug_msg - ("I believe what we have here is a failure to communicate... libusb says %s but strerror says %s\n", - usb_strerror(), strerror(errno)); - return bytes + 28; // an errno - } - if (bytes >= length) { - if (bytes > length) { - log_debug_msg - ("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n"); - if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet - //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution! - control->gtls_buffer_hack_len += bytes - length; - control->gtls_buffer_hack = (char *) malloc(sizeof(char) * control->gtls_buffer_hack_len); - memcpy(control->gtls_buffer_hack, recv_buffer + length, control->gtls_buffer_hack_len); - } else { // if there is. - control->gtls_buffer_hack = - realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length)); - memcpy(control->gtls_buffer_hack + control->gtls_buffer_hack_len, recv_buffer + length, bytes - length); - control->gtls_buffer_hack_len += bytes - length; - } - } - memcpy(buffer + pos_start_fill, recv_buffer, length); - free(recv_buffer); - if (bytes == length) { - log_debug_msg("Returning how much we received.\n"); - return bytes; - } else { - log_debug_msg("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len); - return length; - } - } - return bytes; -} - -/** Command to start the desired service - * - * @param control The lockdownd client - * @param service The name of the service to start - * - * @return The port number the service was started on or 0 on failure. - */ -iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char *service, int *port) -{ - if (!client || !service || !port) - return IPHONE_E_INVALID_ARG; - - char *host_id = get_host_id(); - if (!host_id) - return IPHONE_E_INVALID_CONF; - if (!client->in_SSL && !lockdownd_start_SSL_session(client, host_id)) - return IPHONE_E_SSL_ERROR; - - - plist_t dict = NULL; - char *XML_content = NULL; - uint32_t length, i = 0, port_loc = 0, bytes = 0; - iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - - free(host_id); - host_id = NULL; - - plist_new_dict(&dict); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartService", strlen("StartService")); - plist_add_dict_element(dict, "Service", PLIST_STRING, (void *) service, strlen(service)); - plist_to_xml(dict, &XML_content, &length); - - /* send to iPhone */ - log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - ret = iphone_lckd_send(client, XML_content, length, &bytes); - - free(XML_content); - XML_content = NULL; - plist_free(dict); - dict = NULL; - - if (IPHONE_E_SUCCESS != ret) - return ret; - - ret = iphone_lckd_recv(client, &XML_content, &bytes); - - if (IPHONE_E_SUCCESS != ret) - return ret; - - xml_to_plist(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - - if (bytes <= 0) - return IPHONE_E_NOT_ENOUGH_DATA; - else { - - plist_t query_node = find_query_node(dict, "Request", "StartService"); - plist_t result_key_node = g_node_next_sibling(query_node); - plist_t result_value_node = g_node_next_sibling(result_key_node); - - plist_t port_key_node = find_node(dict, PLIST_KEY, "Port"); - plist_t port_value_node = g_node_next_sibling(port_key_node); - - plist_type result_key_type; - plist_type result_value_type; - plist_type port_key_type; - plist_type port_value_type; - char *result_key = NULL; - char *result_value = NULL; - char *port_key = NULL; - uint64_t res_key_length = 0; - uint64_t res_val_length = 0; - uint64_t port_key_length = 0; - uint64_t port_val_length = 0; - uint64_t port_value = 0; - - get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &res_key_length); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &res_val_length); - get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key), &port_key_length); - get_type_and_value(port_value_node, &port_value_type, (void *) (&port_value), &port_val_length); - - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && - port_key_type == PLIST_KEY && - port_value_type == PLIST_UINT && - !strcmp(result_key, "Result") && !strcmp(result_value, "Success") && !strcmp(port_key, "Port")) { - port_loc = port_value; - ret = IPHONE_E_SUCCESS; - } - - log_debug_msg("lockdownd_start_service(): DATA RECEIVED:\n\n"); - log_debug_msg(XML_content); - log_debug_msg("end data received by lockdownd_start_service()\n"); - - free(XML_content); - plist_free(dict); - dict = NULL; - if (port && ret == IPHONE_E_SUCCESS) { - *port = port_loc; - return IPHONE_E_SUCCESS; - } else - return IPHONE_E_UNKNOWN_ERROR; - } - - return IPHONE_E_UNKNOWN_ERROR; -} diff --git a/src/lockdown.h b/src/lockdown.h deleted file mode 100644 index 8b3dd41..0000000 --- a/src/lockdown.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * lockdown.h - * Defines lockdown stuff, like the client struct. - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOCKDOWND_H -#define LOCKDOWND_H - -#include "usbmux.h" -#include "plist.h" - -#include -#include -#include - - - - -struct iphone_lckd_client_int { - iphone_umux_client_t connection; - gnutls_session_t *ssl_session; - int in_SSL; - char *gtls_buffer_hack; - int gtls_buffer_hack_len; -}; - -iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone); -iphone_error_t lockdownd_hello(iphone_lckd_client_t control); -iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *req_key, char *req_string, - gnutls_datum_t * value); -iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid); -iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key); - -iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert, - gnutls_datum_t * host_cert, gnutls_datum_t * root_cert); -iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, char *host_id); -void lockdownd_close(iphone_lckd_client_t control); - -// SSL functions - -iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const char *HostID); -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length); -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length); - - -#endif diff --git a/src/usbmux.c b/src/usbmux.c deleted file mode 100644 index f0499fa..0000000 --- a/src/usbmux.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * usbmux.c - * Interprets the usb multiplexing protocol used by the iPhone. - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include - -#include "usbmux.h" - -static iphone_umux_client_t *connlist = NULL; -static int clients = 0; - -/** Creates a USBMux packet for the given set of ports. - * - * @param s_port The source port for the connection. - * @param d_port The destination port for the connection. - * - * @return A USBMux packet - */ -usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port) -{ - usbmux_tcp_header *conn = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); - conn->type = htonl(6); - conn->length = 28; - conn->sport = htons(s_port); - conn->dport = htons(d_port); - conn->scnt = 0; - conn->ocnt = 0; - conn->offset = 0x50; - conn->window = htons(0x0200); - conn->nullnull = 0x0000; - conn->length16 = 28; - return conn; -} - -/** Creates a USBMux header containing version information - * - * @return A USBMux header - */ -usbmux_version_header *version_header() -{ - usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_version_header)); - version->type = 0; - version->length = htonl(20); - version->major = htonl(1); - version->minor = 0; - version->allnull = 0; - return version; -} - - -// Maintenance functions. - -/** Removes a connection from the list of connections made. - * The list of connections is necessary for buffering. - * - * @param connection The connection to delete from the tracking list. - */ -void delete_connection(iphone_umux_client_t connection) -{ - iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1)); - int i = 0, j = 0; - for (i = 0; i < clients; i++) { - if (connlist[i] == connection) - continue; - else { - newlist[j] = connlist[i]; - j++; - } - } - free(connlist); - connlist = newlist; - clients--; - if (connection->recv_buffer) - free(connection->recv_buffer); - if (connection->header) - free(connection->header); - connection->r_len = 0; - free(connection); -} - -/** Adds a connection to the list of connections made. - * The connection list is necessary for buffering. - * - * @param connection The connection to add to the global list of connections. - */ - -void add_connection(iphone_umux_client_t connection) -{ - iphone_umux_client_t *newlist = - (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1)); - newlist[clients] = connection; - connlist = newlist; - clients++; -} - -/** Initializes a connection on phone, with source port s_port and destination port d_port - * - * @param device The iPhone to initialize a connection on. - * @param src_port The source port - * @param dst_port The destination port -- 0xf27e for lockdownd. - * @param client A mux TCP header for the connection which is used for tracking and data transfer. - * @return IPHONE_E_SUCCESS on success, an error code otherwise. - */ -iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port, - iphone_umux_client_t * client) -{ - if (!device || !src_port || !dst_port) - return IPHONE_E_INVALID_ARG; - - int bytes = 0; - // Initialize connection stuff - iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int)); - new_connection->header = new_mux_packet(src_port, dst_port); - - // blargg - if (new_connection && new_connection->header) { - new_connection->header->tcp_flags = 0x02; - new_connection->header->length = htonl(new_connection->header->length); - new_connection->header->length16 = htons(new_connection->header->length16); - - if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { - usbmux_tcp_header *response; - response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); - bytes = recv_from_phone(device, (char *) response, sizeof(*response)); - if (response->tcp_flags != 0x12) { - free(response); - return IPHONE_E_UNKNOWN_ERROR; - } else { - free(response); - - log_debug_msg("mux_connect: connection success\n"); - new_connection->header->tcp_flags = 0x10; - new_connection->header->scnt = 1; - new_connection->header->ocnt = 1; - new_connection->phone = device; - new_connection->recv_buffer = NULL; - new_connection->r_len = 0; - add_connection(new_connection); - *client = new_connection; - return IPHONE_E_SUCCESS; - } - } else { - return IPHONE_E_NOT_ENOUGH_DATA; - } - } - // if we get to this point it's probably bad - return IPHONE_E_UNKNOWN_ERROR; -} - -/** Cleans up the given USBMux connection. - * @note Once a connection is closed it may not be used again. - * - * @param connection The connection to close. - * - * @return IPHONE_E_SUCCESS on success. - */ -iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) -{ - if (!client || !client->phone) - return; - - client->header->tcp_flags = 0x04; - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); - int bytes = 0; - - bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("iphone_muxèfree_client(): when writing, libusb gave me the error: %s\n", usb_strerror()); - - bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror()); - - delete_connection(client); - - return IPHONE_E_SUCCESS; -} - - -/** Sends the given data over the selected connection. - * - * @param phone The iPhone to send to. - * @param client The client we're sending data on. - * @param data A pointer to the data to send. - * @param datalen How much data we're sending. - * @param sent_bytes The number of bytes sent, minus the header (28) - * - * @return IPHONE_E_SUCCESS on success. - */ - -iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes) -{ - if (!client->phone || !client || !data || datalen == 0 || !sent_bytes) - return IPHONE_E_INVALID_ARG; - // client->scnt and client->ocnt should already be in host notation... - // we don't need to change them juuuust yet. - *sent_bytes = 0; - log_debug_msg("mux_send(): client wants to send %i bytes\n", datalen); - char *buffer = (char *) malloc(sizeof(usbmux_tcp_header) + datalen + 2); // allow 2 bytes of safety padding - // Set the length and pre-emptively htonl/htons it - client->header->length = htonl(sizeof(usbmux_tcp_header) + datalen); - client->header->length16 = htons(sizeof(usbmux_tcp_header) + datalen); - - // Put scnt and ocnt into big-endian notation - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); - // Concatenation of stuff in the buffer. - memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); - memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen); - - // We have a buffer full of data, we should now send it to the phone. - log_debug_msg("actually sending %zi bytes of data at %p\n", sizeof(usbmux_tcp_header) + datalen, buffer); - - - *sent_bytes = send_to_phone(client->phone, buffer, sizeof(usbmux_tcp_header) + datalen); - log_debug_msg("mux_send: sent %i bytes!\n", *sent_bytes); - // Now that we've sent it off, we can clean up after our sloppy selves. - dump_debug_buffer("packet", buffer, *sent_bytes); - if (buffer) - free(buffer); - // Re-calculate scnt and ocnt - client->header->scnt = ntohl(client->header->scnt) + datalen; - client->header->ocnt = ntohl(client->header->ocnt); - - // Revert lengths - client->header->length = ntohl(client->header->length); - client->header->length16 = ntohs(client->header->length16); - - // Now return the bytes. - if (*sent_bytes < sizeof(usbmux_tcp_header) + datalen) { - *sent_bytes = 0; - return IPHONE_E_NOT_ENOUGH_DATA; - } else { - *sent_bytes = *sent_bytes - 28; // actual length sent. :/ - } - - return IPHONE_E_SUCCESS; -} - -/** This is a higher-level USBMuxTCP-like function - * - * @param connection The connection to receive data on. - * @param data Where to put the data we receive. - * @param datalen How much data to read. - * - * @return How many bytes were read, or -1 if something bad happens. - */ -iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) -{ - - if (!client || !data || datalen == 0 || !recv_bytes) - return IPHONE_E_INVALID_ARG; - /* - * Order of operation: - * 1.) Check if the client has a pre-received buffer. - * 2.) If so, fill data with the buffer, as much as needed. - * a.) Return quickly if the buffer has enough - * b.) If the buffer is only part of the datalen, get the rest of datalen (and if we can't, just return) - * 3.) If not, receive directly from the phone. - * a.) Check incoming packet's ports. If proper, follow proper buffering and receiving operation. - * b.) If not, find the client the ports belong to and fill that client's buffer, then return mux_recv with the same args to try again. - */ - log_debug_msg("mux_recv: datalen == %i\n", datalen); - int bytes = 0, i = 0, complex = 0, offset = 0; - *recv_bytes = 0; - char *buffer = NULL; - usbmux_tcp_header *header = NULL; - - if (client->recv_buffer) { - if (client->r_len >= datalen) { - memcpy(data, client->recv_buffer, datalen); - if (client->r_len == datalen) { - // reset everything - free(client->recv_buffer); - client->r_len = 0; - client->recv_buffer = NULL; - } else { - buffer = (char *) malloc(sizeof(char) * (client->r_len - datalen)); - memcpy(buffer, client->recv_buffer + datalen, (client->r_len - datalen)); - client->r_len -= datalen; - free(client->recv_buffer); - client->recv_buffer = buffer; - } - - // Since we were able to fill the data straight from our buffer, we can just return datalen. See 2a above. - return datalen; - } else { - memcpy(data, client->recv_buffer, client->r_len); - free(client->recv_buffer); // don't need to deal with anymore, but... - offset = client->r_len; // see #2b, above - client->r_len = 0; - } - } // End of what to do if we have a pre-buffer. See #1 and #2 above. - - buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) - - // See #3. - bytes = recv_from_phone(client->phone, buffer, 131072); - if (bytes < 28) { - free(buffer); - log_debug_msg("mux_recv: Did not even get the header.\n"); - return IPHONE_E_NOT_ENOUGH_DATA; - } - - header = (usbmux_tcp_header *) buffer; - if (header->sport != client->header->dport || header->dport != client->header->sport) { - // Ooooops -- we got someone else's packet. - // We gotta stick it in their buffer. (Take that any old way you want ;) ) - for (i = 0; i < clients; i++) { - if (connlist[i]->header->sport == header->dport && connlist[i]->header->dport == header->sport) { - // we have a winner. - char *nfb = (char *) malloc(sizeof(char) * (connlist[i]->r_len + (bytes - 28))); - if (connlist[i]->recv_buffer && connlist[i]->r_len) { - memcpy(nfb, connlist[i]->recv_buffer, connlist[i]->r_len); - free(connlist[i]->recv_buffer); - } - connlist[i]->r_len += bytes - 28; - //connlist[i]->recv_buffer = (char*)realloc(connlist[i]->recv_buffer, sizeof(char) * client->r_len); // grow their buffer - connlist[i]->recv_buffer = nfb; - nfb = NULL; // A cookie for you if you can guess what "nfb" means. - complex = connlist[i]->r_len - (bytes - 28); - memcpy(connlist[i]->recv_buffer + complex, buffer + 28, bytes - 28); // paste into their buffer - connlist[i]->header->ocnt += bytes - 28; - } - } - // If it wasn't ours, it's been handled by this point... or forgotten. - // Free our buffer and continue. - free(buffer); - buffer = NULL; - return iphone_mux_recv(client, data, datalen, recv_bytes); // recurse back in to try again - } - // The packet was absolutely meant for us if it hits this point. - // The pre-buffer has been taken care of, so, again, if we're at this point we have to read from the phone. - - if ((bytes - 28) > datalen) { - // Copy what we need into the data, buffer the rest because we can. - memcpy(data + offset, buffer + 28, datalen); // data+offset: see #2b, above - complex = client->r_len + (bytes - 28) - datalen; - client->recv_buffer = (char *) realloc(client->recv_buffer, (sizeof(char) * complex)); - client->r_len = complex; - complex = client->r_len - (bytes - 28) - datalen; - memcpy(client->recv_buffer + complex, buffer + 28 + datalen, (bytes - 28) - datalen); - free(buffer); - client->header->ocnt += bytes - 28; - *recv_bytes = datalen; - return IPHONE_E_SUCCESS; - } else { - // Fill the data with what we have, and just return. - memcpy(data + offset, buffer + 28, bytes - 28); // data+offset: see #2b, above - client->header->ocnt += bytes - 28; - free(buffer); - *recv_bytes = bytes - 28; - return IPHONE_E_SUCCESS; - } - - // If we get to this point, 'tis probably bad. - log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); - return IPHONE_E_UNKNOWN_ERROR; -} diff --git a/src/usbmux.h b/src/usbmux.h deleted file mode 100644 index 4b18e07..0000000 --- a/src/usbmux.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * usbmux.h - * Defines structures and variables pertaining to the usb multiplexing. - * - * Copyright (c) 2008 Zach C. 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include "libiphone/libiphone.h" - -#ifndef USBMUX_H -#define USBMUX_H - -#ifndef IPHONE_H -#include "iphone.h" -#endif - -typedef struct { - uint32_t type, length; - uint16_t sport, dport; - uint32_t scnt, ocnt; - uint8_t offset, tcp_flags; - uint16_t window, nullnull, length16; -} usbmux_tcp_header; - -struct iphone_umux_client_int { - usbmux_tcp_header *header; - iphone_device_t phone; - char *recv_buffer; - int r_len; -}; - -usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port); - -typedef struct { - uint32_t type, length, major, minor, allnull; -} usbmux_version_header; - -usbmux_version_header *version_header(); - - -#endif diff --git a/src/userpref.c b/src/userpref.c deleted file mode 100644 index b707957..0000000 --- a/src/userpref.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * userpref.c - * contains methods to access user specific certificates IDs and more. - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include "userpref.h" -#include "utils.h" -#include -#include - -#define LIBIPHONE_CONF_DIR "libiphone" -#define LIBIPHONE_CONF_FILE "libiphonerc" - -#define LIBIPHONE_ROOT_PRIVKEY "RootPrivateKey.pem" -#define LIBIPHONE_HOST_PRIVKEY "HostPrivateKey.pem" -#define LIBIPHONE_ROOT_CERTIF "RootCertificate.pem" -#define LIBIPHONE_HOST_CERTIF "HostCertificate.pem" - - -/** Creates a freedesktop compatible configuration directory for libiphone. - */ -inline void create_config_dir() -{ - gchar *config_dir = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, NULL); - - if (!g_file_test(config_dir, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) - g_mkdir_with_parents(config_dir, 0755); - - g_free(config_dir); -} - - -/** Reads the HostID from a previously generated configuration file. - * - * @note It is the responsibility of the calling function to free the returned host_id - * - * @return The string containing the HostID or NULL - */ -char *get_host_id() -{ - char *host_id = NULL; - gchar *config_file; - GKeyFile *key_file; - gchar *loc_host_id; - - config_file = - g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL); - - /* now parse file to get the HostID */ - key_file = g_key_file_new(); - if (g_key_file_load_from_file(key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL)) { - loc_host_id = g_key_file_get_value(key_file, "Global", "HostID", NULL); - if (loc_host_id) - host_id = strdup((char *) loc_host_id); - g_free(loc_host_id); - } - g_key_file_free(key_file); - g_free(config_file); - - log_debug_msg("get_host_id(): Using %s as HostID\n", host_id); - return host_id; -} - -/** Determines whether this iPhone has been connected to this system before. - * - * @param uid The device uid as given by the iPhone. - * - * @return 1 if the iPhone has been connected previously to this configuration - * or 0 otherwise. - */ -int is_device_known(char *uid) -{ - int ret = 0; - gchar *config_file; - GKeyFile *key_file; - gchar **devices_list, **pcur, *keyfilepath, *stored_key; - GIOChannel *keyfile; - - /* first get config file */ - gchar *device_file = g_strconcat(uid, ".pem", NULL); - config_file = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, device_file, NULL); - if (g_file_test(config_file, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) - ret = 1; - g_free(config_file); - g_free(device_file); - return ret; -} - -/** Mark the iPhone (as represented by the key) as having connected to this - * configuration. - * - * @param public_key The public key given by the iPhone - * - * @return 1 on success and 0 if no public key is given or if it has already - * been marked as connected previously. - */ -int store_device_public_key(char *uid, gnutls_datum_t public_key) -{ - - if (NULL == public_key.data || is_device_known(uid)) - return 0; - - /* ensure config directory exists */ - create_config_dir(); - - /* build file path */ - gchar *device_file = g_strconcat(uid, ".pem", NULL); - gchar *pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, device_file, NULL); - - /* store file */ - FILE *pFile = fopen(pem, "wb"); - fwrite(public_key.data, 1, public_key.size, pFile); - fclose(pFile); - g_free(pem); - g_free(device_file); - return 1; -} - -/** Private function which reads the given file into a gnutls structure. - * - * @param file The filename of the file to read - * @param data The pointer at which to store the data. - * - * @return 1 if the file contents where read successfully and 0 otherwise. - */ -int read_file_in_confdir(char *file, gnutls_datum_t * data) -{ - gboolean success; - gsize size; - char *content; - gchar *filepath; - - if (NULL == file || NULL == data) - return 0; - - /* Read file */ - filepath = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, file, NULL); - success = g_file_get_contents(filepath, &content, &size, NULL); - g_free(filepath); - - /* Add it to the gnutls_datnum_t structure */ - data->data = content; - data->size = size; - - return success; -} - -/** Read the root private key - * - * @param root_privkey A pointer to the appropriate gnutls structure - * - * @return 1 if the file was successfully read and 0 otherwise. - */ -int get_root_private_key(gnutls_datum_t * root_privkey) -{ - return read_file_in_confdir(LIBIPHONE_ROOT_PRIVKEY, root_privkey); -} - -/** Read the host private key - * - * @param host_privkey A pointer to the appropriate gnutls structure - * - * @return 1 if the file was successfully read and 0 otherwise. - */ -int get_host_private_key(gnutls_datum_t * host_privkey) -{ - return read_file_in_confdir(LIBIPHONE_HOST_PRIVKEY, host_privkey); -} - -/** Read the root certificate - * - * @param root_privkey A pointer to the appropriate gnutls structure - * - * @return 1 if the file was successfully read and 0 otherwise. - */ -int get_root_certificate(gnutls_datum_t * root_cert) -{ - return read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, root_cert); -} - -/** Read the host certificate - * - * @param root_privkey A pointer to the appropriate gnutls structure - * - * @return 1 if the file was successfully read and 0 otherwise. - */ -int get_host_certificate(gnutls_datum_t * host_cert) -{ - return read_file_in_confdir(LIBIPHONE_HOST_CERTIF, host_cert); -} - -/** Create and save a configuration file containing the given data. - * - * @note: All fields must specified and be non-null - * - * @param host_id The UUID of the host - * @param root_key The root key - * @param host_key The host key - * @param root_cert The root certificate - * @param host_cert The host certificate - * - * @return 1 on success and 0 otherwise. - */ -int init_config_file(char *host_id, gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert, - gnutls_datum_t * host_cert) -{ - FILE *pFile; - gchar *pem; - GKeyFile *key_file; - gsize length; - gchar *buf, *config_file; - GIOChannel *file; - - if (!host_id || !root_key || !host_key || !root_cert || !host_cert) - return 0; - - /* Make sure config directory exists */ - create_config_dir(); - - /* Now parse file to get the HostID */ - key_file = g_key_file_new(); - - /* Store in config file */ - log_debug_msg("init_config_file(): setting hostID to %s\n", host_id); - g_key_file_set_value(key_file, "Global", "HostID", host_id); - - /* Write config file on disk */ - buf = g_key_file_to_data(key_file, &length, NULL); - config_file = - g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL); - file = g_io_channel_new_file(config_file, "w", NULL); - g_free(config_file); - g_io_channel_write_chars(file, buf, length, NULL, NULL); - g_io_channel_shutdown(file, TRUE, NULL); - g_io_channel_unref(file); - - g_key_file_free(key_file); - - /* Now write keys and certificates to disk */ - pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_PRIVKEY, NULL); - pFile = fopen(pem, "wb"); - fwrite(root_key->data, 1, root_key->size, pFile); - fclose(pFile); - g_free(pem); - - pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_HOST_PRIVKEY, NULL); - pFile = fopen(pem, "wb"); - fwrite(host_key->data, 1, host_key->size, pFile); - fclose(pFile); - g_free(pem); - - pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_CERTIF, NULL); - pFile = fopen(pem, "wb"); - fwrite(root_cert->data, 1, root_cert->size, pFile); - fclose(pFile); - g_free(pem); - - pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_HOST_CERTIF, NULL); - pFile = fopen(pem, "wb"); - fwrite(host_cert->data, 1, host_cert->size, pFile); - fclose(pFile); - g_free(pem); - - return 1; -} diff --git a/src/userpref.h b/src/userpref.h deleted file mode 100644 index 450549f..0000000 --- a/src/userpref.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * userpref.h - * contains methods to access user specific certificates IDs and more. - * - * Copyright (c) 2008 Jonathan Beck 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 - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef USERPREF_H -#define USERPREF_H - -#include -/** - * Method to get user's HostID. Caller must free returned buffer. - * - * @return the HostID if exist in config file. Returns NULL otherwise. - */ -char *get_host_id(); - -/** - * Determine if we already paired this device. - * - * @return 1 if device is already paired. Returns 0 otherwise. - */ -int is_device_known(char *uid); - -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int store_device_public_key(char *uid, gnutls_datum_t public_key); - -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_root_private_key(gnutls_datum_t * root_privkey); - -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_host_private_key(gnutls_datum_t * host_privkey); - -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_root_certificate(gnutls_datum_t * root_cert); - -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_host_certificate(gnutls_datum_t * host_cert); - -/** - * Setup a brand new config file. - * @return 1 if everything went well. Returns 0 otherwise. - */ -int init_config_file(char *host_id, gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert, - gnutls_datum_t * host_cert); -#endif -- cgit v1.1-32-gdbae