From f4c4b783c8dbe2fe8e7e6f6b5f19f0d44b489c9a Mon Sep 17 00:00:00 2001 From: Zach C Date: Sun, 31 Aug 2008 11:25:22 -0700 Subject: Added binary-plist support (tweaked slightly to move stuff around) Signed-off-by: Matt Colyer fix makefile to take correct main function into account --- dev/Makefile.am | 9 +- dev/plutil.c | 171 ++++++++++++++++++++++++++++++++++ dev/plutil.h | 13 +++ src/AFC.c | 46 ++++----- src/AFC.h | 10 +- src/lockdown.c | 14 +-- src/plist.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/plist.h | 38 ++++++++ src/usbmux.c | 2 +- src/usbmux.h | 20 ++-- 10 files changed, 557 insertions(+), 50 deletions(-) create mode 100644 dev/plutil.c create mode 100644 dev/plutil.h diff --git a/dev/Makefile.am b/dev/Makefile.am index 4833728..95b4d61 100644 --- a/dev/Makefile.am +++ b/dev/Makefile.am @@ -3,7 +3,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) -bin_PROGRAMS = iphoneclient lckd-client afccheck +bin_PROGRAMS = iphoneclient lckd-client afccheck plutil iphoneclient_SOURCES = main.c iphoneclient_LDADD = ../src/libiphone.la @@ -16,4 +16,9 @@ lckd_client_LDADD = ../src/libiphone.la afccheck_SOURCES = afccheck.c afccheck_CFLAGS = $(AM_CFLAGS) afccheck_LDFLAGS = $(AM_LDFLAGS) -afccheck_LDADD = ../src/libiphone.la \ No newline at end of file +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/plutil.c b/dev/plutil.c new file mode 100644 index 0000000..208d7df --- /dev/null +++ b/dev/plutil.c @@ -0,0 +1,171 @@ +/* + * main.c for plistutil + * right now just prints debug shit + */ + +#include "../src/plist.h" +#include "plutil.h" + +int debug = 0; + +void print_nodes(bplist_node *root_node) { + // Yay, great. Let's print the list of nodes recursively... + int i = 0; + if (!root_node) return; // or not, because the programmer's stupid. + + switch (root_node->type) { + case BPLIST_DICT: + printf("Dictionary node.\nLength %i\n", root_node->length); + for (i = 0; i < (root_node->length * 2); i+=2) { + // HI! + printf("Key: "); + print_nodes(root_node->subnodes[i]); + printf("Value: "); + print_nodes(root_node->subnodes[i+1]); + } + printf("End dictionary node.\n\n"); + break; + + case BPLIST_ARRAY: + printf("Array node.\n"); + for (i = 0; i < root_node->length; i++) { + printf("\tElement %i: ", i); + print_nodes(root_node->subnodes[i]); + } + break; + + case BPLIST_INT: + if (root_node->length == sizeof(uint8_t)) { + printf("Integer: %i\n", root_node->intval8); + } else if (root_node->length == sizeof(uint16_t)) { + printf("Integer: %i\n", root_node->intval16); + } else if (root_node->length == sizeof(uint32_t)) { + printf("Integer: %i\n", root_node->intval32); + } + break; + + case BPLIST_STRING: + case BPLIST_DATA: + printf("String/data: "); + fwrite(root_node->strval, sizeof(char), root_node->length, stdout); + fflush(stdout); + printf("\n"); + break; + + case BPLIST_UNICODE: + printf("Unicode data, may appear crappy: "); + fwrite(root_node->unicodeval, sizeof(wchar_t), root_node->length, stdout); + fflush(stdout); + printf("\n"); + break; + + case BPLIST_TRUE: + printf("True.\n"); + break; + + case BPLIST_FALSE: + printf("False.\n"); + break; + + case BPLIST_REAL: + case BPLIST_DATE: + printf("Real(?): %f\n", root_node->realval); + break; + + default: + printf("oops\nType set to %x and length is %i\n", root_node->type, root_node->length); + break; + } +} + +int main(int argc, char *argv[]) { + struct stat *filestats = (struct stat *)malloc(sizeof(struct stat)); + uint32_t position = 0; + Options *options = parse_arguments(argc, argv); + int argh = 0; + + printf("plistutil version 0.2 written by FxChiP\n"); + + if (!options) { + print_usage(); + return 0; + } + + debug = options->debug; + + FILE *bplist = fopen(options->in_file, "r"); + + stat(options->in_file, filestats); + + printf("here?\n"); + char *bplist_entire = (char*)malloc(sizeof(char) * (filestats->st_size + 1)); + //argh = fgets(bplist_entire, filestats->st_size, bplist); + argh = fread(bplist_entire, sizeof(char), filestats->st_size, bplist); + printf("read %i bytes\n", argh); + fclose(bplist); + printf("or here?\n"); + // bplist_entire contains our stuff + bplist_node *root_node; + root_node = parse_nodes(bplist_entire, filestats->st_size, &position); + printf("plutil debug mode\n\n"); + printf("file size %i\n\n", filestats->st_size); + if (!root_node) { + printf("Invalid binary plist (or some other error occurred.)\n"); + return 0; + } + print_nodes(root_node); + 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 new file mode 100644 index 0000000..2146307 --- /dev/null +++ b/dev/plutil.h @@ -0,0 +1,13 @@ + +/* + * 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/src/AFC.c b/src/AFC.c index 54ea1bb..899bd47 100644 --- a/src/AFC.c +++ b/src/AFC.c @@ -245,7 +245,7 @@ static int receive_AFC_data(iphone_afc_client_t client, char **dump_here) return retval; } - uint32 param1 = buffer[sizeof(AFCPacket)]; + uint32_t param1 = buffer[sizeof(AFCPacket)]; free(buffer); if (r_packet->operation == AFC_ERROR && !(client->afc_packet->operation == AFC_DELETE && param1 == 7)) { @@ -474,7 +474,7 @@ iphone_error_t iphone_afc_delete_file(iphone_afc_client_t client, const char *pa 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))); + 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) @@ -660,7 +660,7 @@ 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 ag = 0; + uint32_t ag = 0; int bytes = 0, length = 0; char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1)); @@ -795,7 +795,7 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, { char *acknowledgement = NULL; const int MAXIMUM_WRITE_SIZE = 1 << 15; - uint32 zero = 0, bytes_loc = 0, segments = (length / MAXIMUM_WRITE_SIZE), current_count = 0, i = 0; + 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) @@ -812,8 +812,8 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, 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)); - memcpy(out_buffer + 4, (char *) &zero, sizeof(uint32)); + 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) { @@ -845,8 +845,8 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, 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)); - memcpy(out_buffer + 4, (char *) &zero, sizeof(uint32)); + 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); @@ -881,7 +881,7 @@ iphone_error_t iphone_afc_close_file(iphone_afc_client_t client, iphone_afc_file if (!client || !file) return IPHONE_E_INVALID_ARG; char *buffer = malloc(sizeof(char) * 8); - uint32 zero = 0; + uint32_t zero = 0; int bytes = 0; afc_lock(client); @@ -889,8 +889,8 @@ iphone_error_t iphone_afc_close_file(iphone_afc_client_t client, iphone_afc_file log_debug_msg("afc_close_file: File handle %i\n", file->filehandle); // Send command - memcpy(buffer, &file->filehandle, sizeof(uint32)); - memcpy(buffer + sizeof(uint32), &zero, sizeof(zero)); + 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); @@ -926,7 +926,7 @@ iphone_error_t iphone_afc_close_file(iphone_afc_client_t client, iphone_afc_file 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 seekto = 0, bytes = 0, zero = 0; + uint32_t seekto = 0, bytes = 0, zero = 0; if (seekpos < 0) seekpos = file->size - abs(seekpos); @@ -935,12 +935,12 @@ iphone_error_t iphone_afc_seek_file(iphone_afc_client_t client, iphone_afc_file_ // Send the command seekto = seekpos; - memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle - memcpy(buffer + 4, &zero, sizeof(uint32)); // pad - memcpy(buffer + 8, &zero, sizeof(uint32)); // fromwhere - memcpy(buffer + 12, &zero, sizeof(uint32)); // pad - memcpy(buffer + 16, &seekto, sizeof(uint32)); // offset - memcpy(buffer + 20, &zero, sizeof(uint32)); // pad + 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); @@ -979,14 +979,14 @@ iphone_error_t iphone_afc_seek_file(iphone_afc_client_t client, iphone_afc_file_ 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 bytes = 0, zero = 0; + uint32_t bytes = 0, zero = 0; afc_lock(client); // Send command - memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle - memcpy(buffer + 4, &zero, sizeof(uint32)); // pad - memcpy(buffer + 8, &newsize, sizeof(uint32)); // newsize + 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; @@ -1012,7 +1012,7 @@ iphone_error_t iphone_afc_truncate_file(iphone_afc_client_t client, iphone_afc_f } } -uint32 iphone_afc_get_file_handle(iphone_afc_file_t file) +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 index 463c13e..5e4d17c 100644 --- a/src/AFC.h +++ b/src/AFC.h @@ -29,12 +29,12 @@ #include typedef struct { - uint32 header1, header2; - uint32 entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; + uint32_t header1, header2; + uint32_t entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; } AFCPacket; typedef struct { - uint32 filehandle, unknown1, size, unknown2; + uint32_t filehandle, unknown1, size, unknown2; } AFCFilePacket; typedef struct __AFCToken { @@ -51,7 +51,7 @@ struct iphone_afc_client_int { }; struct iphone_afc_file_int { - uint32 filehandle, blocks, size, type; + uint32_t filehandle, blocks, size, type; }; @@ -74,4 +74,4 @@ enum { AFC_WRITE = 0x00000010 }; -uint32 iphone_afc_get_file_handle(iphone_afc_file_t file); +uint32_t iphone_afc_get_file_handle(iphone_afc_file_t file); diff --git a/src/lockdown.c b/src/lockdown.c index 65cbf90..6b8f298 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -127,7 +127,7 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, u return IPHONE_E_INVALID_ARG; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; char *receive; - uint32 datalen = 0, bytes = 0; + uint32_t datalen = 0, bytes = 0; if (!client->in_SSL) ret = iphone_mux_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); @@ -211,7 +211,7 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); key = add_key_str_dict_element(plist, dict, "Request", "QueryType", 1); char *XML_content; - uint32 length; + uint32_t length; xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); ret = iphone_lckd_send(control, XML_content, length, &bytes); @@ -265,7 +265,7 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r char **dictionary = NULL; int bytes = 0, i = 0; char *XML_content = NULL; - uint32 length = 0; + uint32_t length = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; /* Setup DevicePublicKey request plist */ @@ -420,7 +420,7 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch char **dictionary = NULL; int bytes = 0, i = 0; char *XML_content = NULL; - uint32 length = 0; + uint32_t length = 0; char *device_cert_b64 = NULL; char *host_cert_b64 = NULL; @@ -658,7 +658,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); xmlNode *key; char *what2send = NULL, **dictionary = NULL; - uint32 len = 0, bytes = 0, return_me = 0, i = 0; + uint32_t len = 0, bytes = 0, return_me = 0, i = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; // end variables @@ -893,8 +893,8 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char return IPHONE_E_SSL_ERROR; char *XML_query, **dictionary; - uint32 length, i = 0, port_loc = 0, bytes = 0; - uint8 result = 0; + uint32_t length, i = 0, port_loc = 0, bytes = 0; + uint8_t result = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; free(host_id); diff --git a/src/plist.c b/src/plist.c index c4d6bfa..0024577 100644 --- a/src/plist.c +++ b/src/plist.c @@ -23,8 +23,10 @@ #include #include #include +#include "utils.h" #include "plist.h" + const char *plist_base = "\n\ \n\ \n\ @@ -243,3 +245,285 @@ void free_dictionary(char **dictionary) free(dictionary); } + +/* + * Binary propertylist code follows + */ + + +/* + * This is how parsing a bplist is going to have to work: + * - The entire binary plist is going to have to be in memory. + * - A function, parse_nodes(), will have to be a recursive function + * which iterates over the binary plist and reads in elements into bplist_node structs + * and handles them accordingly. The end result should be a somewhat-hierarchical layout + * of bplist_nodes. + * - parse_nodes() will return the first node it encounters, which is usually the "root" node. + */ + +uint32_t uipow(uint32_t value, uint32_t power) { + if (!power) return 1; + int i = 0, oVal = value; + for (i = 1; i < power; i++) { + value *= oVal; + } + return value; +} + +void byte_convert(char *address, size_t size) { + int i = 0, j = 0; + char tmp = '\0'; + + for (i = 0; i < (size / 2); i++) { + tmp = address[i]; + j = ((size-1) + 0) - i; + address[i] = address[j]; + address[j] = tmp; + } +} + +bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t *position, uint8_t ref_size) { + if (!position || !bpbuffer || !bplength) return NULL; + + uint8_t modifier = 0; + bplist_node *new_node = (bplist_node*)malloc(sizeof(bplist_node)); + bplist_node *length_stupidity = NULL; + memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct + + int myPos = *position; + if (myPos == bplength || (myPos+1) == bplength) { free(new_node); return NULL; } // end of string + + uint32_t length = 0; + if (!myPos) { + if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { + return NULL; // badness! + } + myPos += strlen("bplist00"); + } + + // Get the node's type. + if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real + // better handling of date; basically interpret as real or double + new_node->type = BPLIST_DATE; + new_node->length = 8; // always 8 for "date" (Apple intended it, not me) + myPos++; + memcpy(&new_node->realval, bpbuffer+myPos, sizeof(new_node->realval)); + byte_convert(&new_node->realval, sizeof(new_node->realval)); + myPos += new_node->length; + *position = myPos; + return new_node; + } + + new_node->type = bpbuffer[myPos] & BPLIST_MASK; + new_node->length = bpbuffer[myPos] & BPLIST_FILL; + if (!new_node->type) { + // what? check if it's a boolean. + if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) { + // okay, so it is. Carry on. + new_node->type = bpbuffer[myPos]; + new_node->length = 0; + } else { + // er, what? we have a bad type here. Return NULL. + free(new_node); + //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); + return NULL; + } + } + + myPos++; // puts us in the data. + if (new_node->length == BPLIST_FILL) { // Data happens to contain length... + // what? you're going to make me parse an int for the length. You suck. + *position = myPos; + length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); + switch (length_stupidity->length) { + case sizeof(uint8_t): + new_node->length = length_stupidity->intval8; + break; + case sizeof(uint16_t): + new_node->length = length_stupidity->intval16; + break; + case sizeof(uint32_t): + new_node->length = length_stupidity->intval32; + break; + case sizeof(uint64_t): + new_node->length = length_stupidity->intval64; + break; + default: + free(new_node); + free(length_stupidity); + return NULL; + } + // There, we have our fucking length now. + *position = myPos; + free(length_stupidity); // cleanup + } + + // Now we're in the data. + // Error-checking sorta + if ((myPos + new_node->length) >= bplength) { + new_node->length = bplength - myPos; // truncate the object + } + + // And now for the greatest show on earth: the giant fucking switch statement. + switch (new_node->type) { + case BPLIST_INT: + new_node->length = uipow(2, new_node->length); // make length less misleading + switch (new_node->length) { + case sizeof(uint8_t): + new_node->intval8 = bpbuffer[myPos]; + break; + case sizeof(uint16_t): + memcpy(&new_node->intval16, bpbuffer+myPos, sizeof(uint16_t)); + new_node->intval16 = ntohs(new_node->intval16); + break; + case sizeof(uint32_t): + memcpy(&new_node->intval32, bpbuffer+myPos, sizeof(uint32_t)); + new_node->intval32 = ntohl(new_node->intval32); + break; + case sizeof(uint64_t): + memcpy(&new_node->intval64, bpbuffer+myPos, sizeof(uint64_t)); + byte_convert(&new_node->intval64, sizeof(uint64_t)); + break; + default: + free(new_node); + printf("parse_raw_node: lol: invalid int: size given %i\n", new_node->length); + printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); + return NULL; + } + break; + + case BPLIST_REAL: + new_node->length = uipow(2, new_node->length); + memcpy(&new_node->realval, bpbuffer+myPos, new_node->length); // XXX: probable buffer overflow here + //new_node->realval = bpbuffer[myPos]; // why not + byte_convert(&new_node->realval, sizeof(double)); + break; + + case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ + new_node->length = new_node->length * 2; // dicts lie + case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ + new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. + case BPLIST_STRING: + case BPLIST_DATA: + default: /* made to hold raw data. */ + modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1; + new_node->strval = (char*)malloc(sizeof(char) * (new_node->length * modifier)); + memcpy(new_node->strval, bpbuffer+myPos, (new_node->length * modifier)); + break; + + case BPLIST_UNICODE: + new_node->unicodeval = (wchar_t*)malloc(sizeof(wchar_t) * new_node->length); + memcpy(new_node->unicodeval, bpbuffer+myPos, new_node->length); + break; + } + + myPos += new_node->length; + *position = myPos; + return new_node; +} + +void print_bytes(char *val, size_t size) { + int i = 0; + for (i = 0; i < size; i++) { + printf("Byte %i: 0x%x\n", i, val[i]); + } +} + +bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t *position) { + bplist_node **nodeslist = NULL, **newaddr = NULL; + bplist_node *new_node = NULL, *root_node = NULL; + + uint32_t nodeslength = 0; + uint8_t offset_size = 0, dict_param_size = 0; + offset_size = bpbuffer[bplength-26]; + dict_param_size = bpbuffer[bplength-25]; + uint64_t current_offset = 0; + //uint64_t num_objects = *(bpbuffer+(bplength-24)), root_object = *(bpbuffer+(bplength-16)), offset_table_index = *(bpbuffer+(bplength-8)); + uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; + memcpy(&num_objects, bpbuffer+bplength-24, sizeof(uint64_t)); + memcpy(&root_object, bpbuffer+bplength-16, sizeof(uint64_t)); + memcpy(&offset_table_index, bpbuffer+bplength-8, sizeof(uint64_t)); + byte_convert(&num_objects, sizeof(uint64_t)); + byte_convert(&root_object, sizeof(uint64_t)); + byte_convert(&offset_table_index, sizeof(uint64_t)); + + log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength-26]); + log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength-25]); + log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer+bplength-24)); + log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer+bplength-16)); + log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer+bplength-8)); + log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); + + int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; + uint32_t index1 = 0, index2 = 0; + + nodeslist = (bplist_node**)malloc(sizeof(bplist_node*) * num_objects); + if (!nodeslist) return NULL; + + for (i = 0; i < num_objects; i++) { + memcpy(¤t_offset, bpbuffer+(offset_table_index+(i*offset_size)), offset_size); + //current_offset = (offset_size == 2) ? ntohs(current_offset) : (offset_size == 4) ? ntohl(current_offset) : current_offset; + //if (offset_size == 8) byte_convert(¤t_offset, 8); + byte_convert(¤t_offset, (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); + log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); + nodeslist[i] = parse_raw_node(bpbuffer, bplength, ¤t_offset, dict_param_size); + log_debug_msg("parse_nodes: parse_raw_node done\n"); + } + + + for (i = 0; i < num_objects; i++) { + // set elements for dicts and arrays and leave the rest alone + log_debug_msg("parse_nodes: on node %i\n", i); + switch (nodeslist[i]->type) { + case BPLIST_DICT: + log_debug_msg("parse_nodes: dictionary found\n"); + nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); + for (j = 0; j < (nodeslist[i]->length / 2); j++) { + str_i = j * nodeslist[i]->intval8; + str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8; + + memcpy(&index1, nodeslist[i]->strval+str_i, nodeslist[i]->intval8); + memcpy(&index2, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); + //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; + //index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2; + byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); + byte_convert(&index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); + //printf("parse_nodes: key index %i value %i\n", index1, index2); + //printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length); + //printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length); + nodeslist[i]->subnodes[k++] = nodeslist[index1]; + nodeslist[i]->subnodes[k++] = nodeslist[index2]; + } + + nodeslist[i]->length = nodeslist[i]->length / 2; + free(nodeslist[i]->strval); + k = 0; + break; + + case BPLIST_ARRAY: + log_debug_msg("parse_nodes: array found\n"); + nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data + + for (j = 0; j < nodeslist[i]->length; j++) { + log_debug_msg("parse_nodes: array index %i\n", j); + str_j = j * nodeslist[i]->intval8; + //index1 = nodeslist[i]->strval[j]; + memcpy(&index1, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); + log_debug_msg("parse_nodes: post-memcpy\n"); + //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; + byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); + log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); + nodeslist[i]->subnodes[j] = nodeslist[index1]; + log_debug_msg("parse_nodes: post-assignment\n"); + } + free(nodeslist[i]->strval); + break; + default: + //printf("lol... type %x\n", nodeslist[i]->type); + break; + } // those are the only two we need to correct for. + } + + root_node = nodeslist[root_object]; + return root_node; +} diff --git a/src/plist.h b/src/plist.h index b27a0c5..98c7d91 100644 --- a/src/plist.h +++ b/src/plist.h @@ -24,6 +24,12 @@ #include #include +#include +#include + +#include +#include +#include xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); @@ -35,4 +41,36 @@ xmlDocPtr new_plist(); char **read_dict_element_strings(xmlNode * dict); void free_dictionary(char **dictionary); + +/* Binary plist stuff */ + +enum { + BPLIST_TRUE = 0x08, + BPLIST_FALSE = 0x09, + BPLIST_FILL = 0x0F, /* will be used for length grabbing */ + BPLIST_INT = 0x10, + BPLIST_REAL = 0x20, + BPLIST_DATE = 0x33, + BPLIST_DATA = 0x40, + BPLIST_STRING = 0x50, + BPLIST_UNICODE = 0x60, + BPLIST_UID = 0x70, + BPLIST_ARRAY = 0xA0, + BPLIST_SET = 0xC0, + BPLIST_DICT = 0xD0, + BPLIST_MASK = 0xF0 +}; + +typedef struct _bplist_node { + struct _bplist_node *next, **subnodes; // subnodes is for arrays, dicts and (potentially) sets. + uint64_t length, intval64; + uint32_t intval32; // length = subnodes + uint16_t intval16; + uint8_t intval8; + uint8_t type, *indexes; // indexes for array-types; essentially specify the order in which to access for key => value pairs + char *strval; + double realval; + wchar_t *unicodeval; +} bplist_node; + #endif diff --git a/src/usbmux.c b/src/usbmux.c index 2114758..f0499fa 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -37,7 +37,7 @@ static int clients = 0; * * @return A USBMux packet */ -usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) +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); diff --git a/src/usbmux.h b/src/usbmux.h index da8a361..4b18e07 100644 --- a/src/usbmux.h +++ b/src/usbmux.h @@ -22,6 +22,7 @@ #include #include #include +#include "libiphone/libiphone.h" #ifndef USBMUX_H #define USBMUX_H @@ -30,17 +31,12 @@ #include "iphone.h" #endif -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint8_t uint8; - - typedef struct { - uint32 type, length; - uint16 sport, dport; - uint32 scnt, ocnt; - uint8 offset, tcp_flags; - uint16 window, nullnull, length16; + 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 { @@ -50,10 +46,10 @@ struct iphone_umux_client_int { int r_len; }; -usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port); +usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port); typedef struct { - uint32 type, length, major, minor, allnull; + uint32_t type, length, major, minor, allnull; } usbmux_version_header; usbmux_version_header *version_header(); -- cgit v1.1-32-gdbae From 0bca81e7c8ce5ba53390271e5c7eaa7a5f281c91 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 31 Aug 2008 22:50:37 +0200 Subject: Output binary data base64 encoded (and 60 cols wide) --- dev/plutil.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index 208d7df..1c7b140 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -45,12 +45,19 @@ void print_nodes(bplist_node *root_node) { break; case BPLIST_STRING: - case BPLIST_DATA: - printf("String/data: "); + printf("String: "); fwrite(root_node->strval, sizeof(char), root_node->length, stdout); fflush(stdout); printf("\n"); break; + + case BPLIST_DATA: + printf("Data: "); + char* data = g_base64_encode(root_node->strval,root_node->length); + fwrite(format_string(data, 60, 0), sizeof(char), strlen(data), stdout); + fflush(stdout); + printf("\n"); + break; case BPLIST_UNICODE: printf("Unicode data, may appear crappy: "); -- cgit v1.1-32-gdbae From aed2c025f6e47dc769675e564cc574adc496a88a Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Tue, 25 Nov 2008 19:14:27 +0100 Subject: fix some warnings and indent --- dev/lckdclient.c | 1 + dev/main.c | 2 +- dev/plutil.c | 219 ++++++++++++++++++------------------ src/plist.c | 335 ++++++++++++++++++++++++++++--------------------------- src/plist.h | 11 +- 5 files changed, 294 insertions(+), 274 deletions(-) diff --git a/dev/lckdclient.c b/dev/lckdclient.c index 96bc27d..c96f052 100644 --- a/dev/lckdclient.c +++ b/dev/lckdclient.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include diff --git a/dev/main.c b/dev/main.c index 2dbfb4a..4974eef 100644 --- a/dev/main.c +++ b/dev/main.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) 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", stbuf.st_size); + 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) { diff --git a/dev/plutil.c b/dev/plutil.c index 1c7b140..d1c3ddd 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -5,171 +5,178 @@ #include "../src/plist.h" #include "plutil.h" +#include +#include +#include +#include -int debug = 0; - -void print_nodes(bplist_node *root_node) { +void print_nodes(bplist_node * root_node) +{ // Yay, great. Let's print the list of nodes recursively... int i = 0; - if (!root_node) return; // or not, because the programmer's stupid. - + if (!root_node) + return; // or not, because the programmer's stupid. + switch (root_node->type) { - case BPLIST_DICT: - printf("Dictionary node.\nLength %i\n", root_node->length); - for (i = 0; i < (root_node->length * 2); i+=2) { - // HI! - printf("Key: "); - print_nodes(root_node->subnodes[i]); - printf("Value: "); - print_nodes(root_node->subnodes[i+1]); - } - printf("End dictionary node.\n\n"); - break; - - case BPLIST_ARRAY: - printf("Array node.\n"); - for (i = 0; i < root_node->length; i++) { - printf("\tElement %i: ", i); - print_nodes(root_node->subnodes[i]); - } - break; - - case BPLIST_INT: - if (root_node->length == sizeof(uint8_t)) { - printf("Integer: %i\n", root_node->intval8); - } else if (root_node->length == sizeof(uint16_t)) { - printf("Integer: %i\n", root_node->intval16); - } else if (root_node->length == sizeof(uint32_t)) { - printf("Integer: %i\n", root_node->intval32); - } - break; - - case BPLIST_STRING: - printf("String: "); - fwrite(root_node->strval, sizeof(char), root_node->length, stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_DATA: - printf("Data: "); - char* data = g_base64_encode(root_node->strval,root_node->length); - fwrite(format_string(data, 60, 0), sizeof(char), strlen(data), stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_UNICODE: - printf("Unicode data, may appear crappy: "); - fwrite(root_node->unicodeval, sizeof(wchar_t), root_node->length, stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_TRUE: - printf("True.\n"); - break; - - case BPLIST_FALSE: - printf("False.\n"); - break; - - case BPLIST_REAL: - case BPLIST_DATE: - printf("Real(?): %f\n", root_node->realval); - break; - - default: - printf("oops\nType set to %x and length is %i\n", root_node->type, root_node->length); - break; + case BPLIST_DICT: + printf("Dictionary node.\nLength %lu\n", (long unsigned int) root_node->length); + for (i = 0; i < (root_node->length * 2); i += 2) { + // HI! + printf("Key: "); + print_nodes(root_node->subnodes[i]); + printf("Value: "); + print_nodes(root_node->subnodes[i + 1]); + } + printf("End dictionary node.\n\n"); + break; + + case BPLIST_ARRAY: + printf("Array node.\n"); + for (i = 0; i < root_node->length; i++) { + printf("\tElement %i: ", i); + print_nodes(root_node->subnodes[i]); + } + break; + + case BPLIST_INT: + if (root_node->length == sizeof(uint8_t)) { + printf("Integer: %i\n", root_node->intval8); + } else if (root_node->length == sizeof(uint16_t)) { + printf("Integer: %i\n", root_node->intval16); + } else if (root_node->length == sizeof(uint32_t)) { + printf("Integer: %i\n", root_node->intval32); + } + break; + + case BPLIST_STRING: + printf("String: "); + fwrite(root_node->strval, sizeof(char), root_node->length, stdout); + fflush(stdout); + printf("\n"); + break; + + case BPLIST_DATA: + printf("Data: "); + char *data = g_base64_encode(root_node->strval, root_node->length); + fwrite(format_string(data, 60, 0), sizeof(char), strlen(data), stdout); + fflush(stdout); + printf("\n"); + break; + + case BPLIST_UNICODE: + printf("Unicode data, may appear crappy: "); + fwrite(root_node->unicodeval, sizeof(wchar_t), root_node->length, stdout); + fflush(stdout); + printf("\n"); + break; + + case BPLIST_TRUE: + printf("True.\n"); + break; + + case BPLIST_FALSE: + printf("False.\n"); + break; + + case BPLIST_REAL: + case BPLIST_DATE: + printf("Real(?): %f\n", root_node->realval); + break; + + default: + printf("oops\nType set to %x and length is %lu\n", root_node->type, (long unsigned int) root_node->length); + break; } } -int main(int argc, char *argv[]) { - struct stat *filestats = (struct stat *)malloc(sizeof(struct stat)); +int main(int argc, char *argv[]) +{ + struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); uint32_t position = 0; Options *options = parse_arguments(argc, argv); int argh = 0; - + printf("plistutil version 0.2 written by FxChiP\n"); - + if (!options) { print_usage(); return 0; } - debug = options->debug; - + iphone_set_debug(options->debug); + FILE *bplist = fopen(options->in_file, "r"); - + stat(options->in_file, filestats); printf("here?\n"); - char *bplist_entire = (char*)malloc(sizeof(char) * (filestats->st_size + 1)); + char *bplist_entire = (char *) malloc(sizeof(char) * (filestats->st_size + 1)); //argh = fgets(bplist_entire, filestats->st_size, bplist); argh = fread(bplist_entire, sizeof(char), filestats->st_size, bplist); printf("read %i bytes\n", argh); fclose(bplist); printf("or here?\n"); // bplist_entire contains our stuff - bplist_node *root_node; - root_node = parse_nodes(bplist_entire, filestats->st_size, &position); - printf("plutil debug mode\n\n"); - printf("file size %i\n\n", filestats->st_size); - if (!root_node) { - printf("Invalid binary plist (or some other error occurred.)\n"); - return 0; + bplist_node *root_node; + root_node = parse_nodes(bplist_entire, filestats->st_size, &position); + printf("plutil debug mode\n\n"); + printf("file size %i\n\n", (int) filestats->st_size); + if (!root_node) { + printf("Invalid binary plist (or some other error occurred.)\n"); + return 0; } - print_nodes(root_node); - return 0; - } + print_nodes(root_node); + return 0; +} -Options *parse_arguments(int argc, char *argv[]) { +Options *parse_arguments(int argc, char *argv[]) +{ int i = 0; - - Options *options = (Options*)malloc(sizeof(Options)); + + 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) { + if ((i + 1) == argc) { free(options); return NULL; } - options->in_file = argv[i+1]; + options->in_file = argv[i + 1]; i++; continue; } - + if (!strcmp(argv[i], "--outfile") || !strcmp(argv[i], "-o")) { - if ((i+1) == argc) { + if ((i + 1) == argc) { free(options); return NULL; } - options->out_file = argv[i+1]; + 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*/) { + + if (!options->in_file /*|| !options->out_file */ ) { free(options); return NULL; } - + return options; } -void print_usage() { +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"); diff --git a/src/plist.c b/src/plist.c index 0024577..7a09b4d 100644 --- a/src/plist.c +++ b/src/plist.c @@ -261,8 +261,10 @@ void free_dictionary(char **dictionary) * - parse_nodes() will return the first node it encounters, which is usually the "root" node. */ -uint32_t uipow(uint32_t value, uint32_t power) { - if (!power) return 1; +uint32_t uipow(uint32_t value, uint32_t power) +{ + if (!power) + return 1; int i = 0, oVal = value; for (i = 1; i < power; i++) { value *= oVal; @@ -270,50 +272,55 @@ uint32_t uipow(uint32_t value, uint32_t power) { return value; } -void byte_convert(char *address, size_t size) { +void byte_convert(char *address, size_t size) +{ int i = 0, j = 0; char tmp = '\0'; - + for (i = 0; i < (size / 2); i++) { tmp = address[i]; - j = ((size-1) + 0) - i; + j = ((size - 1) + 0) - i; address[i] = address[j]; address[j] = tmp; } } - -bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t *position, uint8_t ref_size) { - if (!position || !bpbuffer || !bplength) return NULL; - + +bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size) +{ + if (!position || !bpbuffer || !bplength) + return NULL; + uint8_t modifier = 0; - bplist_node *new_node = (bplist_node*)malloc(sizeof(bplist_node)); + bplist_node *new_node = (bplist_node *) malloc(sizeof(bplist_node)); bplist_node *length_stupidity = NULL; - memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct - + memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct + int myPos = *position; - if (myPos == bplength || (myPos+1) == bplength) { free(new_node); return NULL; } // end of string - + if (myPos == bplength || (myPos + 1) == bplength) { + free(new_node); + return NULL; + } // end of string + uint32_t length = 0; if (!myPos) { if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { - return NULL; // badness! + return NULL; // badness! } myPos += strlen("bplist00"); } - // Get the node's type. - if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real + if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real // better handling of date; basically interpret as real or double new_node->type = BPLIST_DATE; - new_node->length = 8; // always 8 for "date" (Apple intended it, not me) + new_node->length = 8; // always 8 for "date" (Apple intended it, not me) myPos++; - memcpy(&new_node->realval, bpbuffer+myPos, sizeof(new_node->realval)); - byte_convert(&new_node->realval, sizeof(new_node->realval)); + memcpy(&new_node->realval, bpbuffer + myPos, sizeof(new_node->realval)); + byte_convert((char *) &new_node->realval, sizeof(new_node->realval)); myPos += new_node->length; *position = myPos; return new_node; } - + new_node->type = bpbuffer[myPos] & BPLIST_MASK; new_node->length = bpbuffer[myPos] & BPLIST_FILL; if (!new_node->type) { @@ -322,151 +329,153 @@ bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t *p // okay, so it is. Carry on. new_node->type = bpbuffer[myPos]; new_node->length = 0; - } else { + } else { // er, what? we have a bad type here. Return NULL. free(new_node); //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); return NULL; } } - - myPos++; // puts us in the data. - if (new_node->length == BPLIST_FILL) { // Data happens to contain length... + + myPos++; // puts us in the data. + if (new_node->length == BPLIST_FILL) { // Data happens to contain length... // what? you're going to make me parse an int for the length. You suck. *position = myPos; length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); switch (length_stupidity->length) { - case sizeof(uint8_t): - new_node->length = length_stupidity->intval8; - break; - case sizeof(uint16_t): - new_node->length = length_stupidity->intval16; - break; - case sizeof(uint32_t): - new_node->length = length_stupidity->intval32; - break; - case sizeof(uint64_t): - new_node->length = length_stupidity->intval64; - break; - default: - free(new_node); - free(length_stupidity); - return NULL; + case sizeof(uint8_t): + new_node->length = length_stupidity->intval8; + break; + case sizeof(uint16_t): + new_node->length = length_stupidity->intval16; + break; + case sizeof(uint32_t): + new_node->length = length_stupidity->intval32; + break; + case sizeof(uint64_t): + new_node->length = length_stupidity->intval64; + break; + default: + free(new_node); + free(length_stupidity); + return NULL; } // There, we have our fucking length now. *position = myPos; - free(length_stupidity); // cleanup + free(length_stupidity); // cleanup } - // Now we're in the data. // Error-checking sorta if ((myPos + new_node->length) >= bplength) { - new_node->length = bplength - myPos; // truncate the object + new_node->length = bplength - myPos; // truncate the object } - // And now for the greatest show on earth: the giant fucking switch statement. switch (new_node->type) { - case BPLIST_INT: - new_node->length = uipow(2, new_node->length); // make length less misleading - switch (new_node->length) { - case sizeof(uint8_t): - new_node->intval8 = bpbuffer[myPos]; - break; - case sizeof(uint16_t): - memcpy(&new_node->intval16, bpbuffer+myPos, sizeof(uint16_t)); - new_node->intval16 = ntohs(new_node->intval16); - break; - case sizeof(uint32_t): - memcpy(&new_node->intval32, bpbuffer+myPos, sizeof(uint32_t)); - new_node->intval32 = ntohl(new_node->intval32); - break; - case sizeof(uint64_t): - memcpy(&new_node->intval64, bpbuffer+myPos, sizeof(uint64_t)); - byte_convert(&new_node->intval64, sizeof(uint64_t)); - break; - default: - free(new_node); - printf("parse_raw_node: lol: invalid int: size given %i\n", new_node->length); - printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); - return NULL; - } + case BPLIST_INT: + new_node->length = uipow(2, new_node->length); // make length less misleading + switch (new_node->length) { + case sizeof(uint8_t): + new_node->intval8 = bpbuffer[myPos]; break; - - case BPLIST_REAL: - new_node->length = uipow(2, new_node->length); - memcpy(&new_node->realval, bpbuffer+myPos, new_node->length); // XXX: probable buffer overflow here - //new_node->realval = bpbuffer[myPos]; // why not - byte_convert(&new_node->realval, sizeof(double)); + case sizeof(uint16_t): + memcpy(&new_node->intval16, bpbuffer + myPos, sizeof(uint16_t)); + new_node->intval16 = ntohs(new_node->intval16); break; - - case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ - new_node->length = new_node->length * 2; // dicts lie - case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ - new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. - case BPLIST_STRING: - case BPLIST_DATA: - default: /* made to hold raw data. */ - modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1; - new_node->strval = (char*)malloc(sizeof(char) * (new_node->length * modifier)); - memcpy(new_node->strval, bpbuffer+myPos, (new_node->length * modifier)); + case sizeof(uint32_t): + memcpy(&new_node->intval32, bpbuffer + myPos, sizeof(uint32_t)); + new_node->intval32 = ntohl(new_node->intval32); break; - - case BPLIST_UNICODE: - new_node->unicodeval = (wchar_t*)malloc(sizeof(wchar_t) * new_node->length); - memcpy(new_node->unicodeval, bpbuffer+myPos, new_node->length); + case sizeof(uint64_t): + memcpy(&new_node->intval64, bpbuffer + myPos, sizeof(uint64_t)); + byte_convert((char *) &new_node->intval64, sizeof(uint64_t)); break; + default: + free(new_node); + printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) new_node->length); + printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); + return NULL; + } + break; + + case BPLIST_REAL: + new_node->length = uipow(2, new_node->length); + memcpy(&new_node->realval, bpbuffer + myPos, new_node->length); // XXX: probable buffer overflow here + //new_node->realval = bpbuffer[myPos]; // why not + byte_convert((char *) &new_node->realval, sizeof(double)); + break; + + case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ + new_node->length = new_node->length * 2; // dicts lie + case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ + new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. + case BPLIST_STRING: + case BPLIST_DATA: + default: /* made to hold raw data. */ + modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1; + new_node->strval = (char *) malloc(sizeof(char) * (new_node->length * modifier)); + memcpy(new_node->strval, bpbuffer + myPos, (new_node->length * modifier)); + break; + + case BPLIST_UNICODE: + new_node->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * new_node->length); + memcpy(new_node->unicodeval, bpbuffer + myPos, new_node->length); + break; } - + myPos += new_node->length; *position = myPos; return new_node; } -void print_bytes(char *val, size_t size) { +void print_bytes(char *val, size_t size) +{ int i = 0; for (i = 0; i < size; i++) { printf("Byte %i: 0x%x\n", i, val[i]); } } -bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t *position) { +bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position) +{ bplist_node **nodeslist = NULL, **newaddr = NULL; bplist_node *new_node = NULL, *root_node = NULL; - + uint32_t nodeslength = 0; uint8_t offset_size = 0, dict_param_size = 0; - offset_size = bpbuffer[bplength-26]; - dict_param_size = bpbuffer[bplength-25]; + offset_size = bpbuffer[bplength - 26]; + dict_param_size = bpbuffer[bplength - 25]; uint64_t current_offset = 0; //uint64_t num_objects = *(bpbuffer+(bplength-24)), root_object = *(bpbuffer+(bplength-16)), offset_table_index = *(bpbuffer+(bplength-8)); uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; - memcpy(&num_objects, bpbuffer+bplength-24, sizeof(uint64_t)); - memcpy(&root_object, bpbuffer+bplength-16, sizeof(uint64_t)); - memcpy(&offset_table_index, bpbuffer+bplength-8, sizeof(uint64_t)); - byte_convert(&num_objects, sizeof(uint64_t)); - byte_convert(&root_object, sizeof(uint64_t)); - byte_convert(&offset_table_index, sizeof(uint64_t)); - - log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength-26]); - log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength-25]); - log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer+bplength-24)); - log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer+bplength-16)); - log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer+bplength-8)); + memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t)); + memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t)); + memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t)); + byte_convert((char *) &num_objects, sizeof(uint64_t)); + byte_convert((char *) &root_object, sizeof(uint64_t)); + byte_convert((char *) &offset_table_index, sizeof(uint64_t)); + + log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]); + log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]); + log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24)); + log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16)); + log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8)); log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); - + int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; uint32_t index1 = 0, index2 = 0; - - nodeslist = (bplist_node**)malloc(sizeof(bplist_node*) * num_objects); - if (!nodeslist) return NULL; + + nodeslist = (bplist_node **) malloc(sizeof(bplist_node *) * num_objects); + if (!nodeslist) + return NULL; for (i = 0; i < num_objects; i++) { - memcpy(¤t_offset, bpbuffer+(offset_table_index+(i*offset_size)), offset_size); + memcpy(¤t_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size); //current_offset = (offset_size == 2) ? ntohs(current_offset) : (offset_size == 4) ? ntohl(current_offset) : current_offset; //if (offset_size == 8) byte_convert(¤t_offset, 8); - byte_convert(¤t_offset, (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); + byte_convert((char *) ¤t_offset, + (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); - nodeslist[i] = parse_raw_node(bpbuffer, bplength, ¤t_offset, dict_param_size); + nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size); log_debug_msg("parse_nodes: parse_raw_node done\n"); } @@ -475,55 +484,55 @@ bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t *posi // set elements for dicts and arrays and leave the rest alone log_debug_msg("parse_nodes: on node %i\n", i); switch (nodeslist[i]->type) { - case BPLIST_DICT: - log_debug_msg("parse_nodes: dictionary found\n"); - nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); - for (j = 0; j < (nodeslist[i]->length / 2); j++) { - str_i = j * nodeslist[i]->intval8; - str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8; - - memcpy(&index1, nodeslist[i]->strval+str_i, nodeslist[i]->intval8); - memcpy(&index2, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); - //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; - //index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2; - byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); - byte_convert(&index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); - //printf("parse_nodes: key index %i value %i\n", index1, index2); - //printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length); - //printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length); - nodeslist[i]->subnodes[k++] = nodeslist[index1]; - nodeslist[i]->subnodes[k++] = nodeslist[index2]; - } - - nodeslist[i]->length = nodeslist[i]->length / 2; - free(nodeslist[i]->strval); - k = 0; - break; - - case BPLIST_ARRAY: - log_debug_msg("parse_nodes: array found\n"); - nodeslist[i]->subnodes = (bplist_node*)malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data - - for (j = 0; j < nodeslist[i]->length; j++) { - log_debug_msg("parse_nodes: array index %i\n", j); - str_j = j * nodeslist[i]->intval8; - //index1 = nodeslist[i]->strval[j]; - memcpy(&index1, nodeslist[i]->strval+str_j, nodeslist[i]->intval8); - log_debug_msg("parse_nodes: post-memcpy\n"); - //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; - byte_convert(&index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); - log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); - nodeslist[i]->subnodes[j] = nodeslist[index1]; - log_debug_msg("parse_nodes: post-assignment\n"); - } - free(nodeslist[i]->strval); - break; - default: - //printf("lol... type %x\n", nodeslist[i]->type); - break; - } // those are the only two we need to correct for. + case BPLIST_DICT: + log_debug_msg("parse_nodes: dictionary found\n"); + nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length); + for (j = 0; j < (nodeslist[i]->length / 2); j++) { + str_i = j * nodeslist[i]->intval8; + str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8; + + memcpy(&index1, nodeslist[i]->strval + str_i, nodeslist[i]->intval8); + memcpy(&index2, nodeslist[i]->strval + str_j, nodeslist[i]->intval8); + //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; + //index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2; + byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); + byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); + //printf("parse_nodes: key index %i value %i\n", index1, index2); + //printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length); + //printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length); + nodeslist[i]->subnodes[k++] = nodeslist[index1]; + nodeslist[i]->subnodes[k++] = nodeslist[index2]; + } + + nodeslist[i]->length = nodeslist[i]->length / 2; + free(nodeslist[i]->strval); + k = 0; + break; + + case BPLIST_ARRAY: + log_debug_msg("parse_nodes: array found\n"); + nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data + + for (j = 0; j < nodeslist[i]->length; j++) { + log_debug_msg("parse_nodes: array index %i\n", j); + str_j = j * nodeslist[i]->intval8; + //index1 = nodeslist[i]->strval[j]; + memcpy(&index1, nodeslist[i]->strval + str_j, nodeslist[i]->intval8); + log_debug_msg("parse_nodes: post-memcpy\n"); + //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; + byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); + log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); + nodeslist[i]->subnodes[j] = nodeslist[index1]; + log_debug_msg("parse_nodes: post-assignment\n"); + } + free(nodeslist[i]->strval); + break; + default: + //printf("lol... type %x\n", nodeslist[i]->type); + break; + } // those are the only two we need to correct for. } - + root_node = nodeslist[root_object]; return root_node; } diff --git a/src/plist.h b/src/plist.h index 98c7d91..5f31281 100644 --- a/src/plist.h +++ b/src/plist.h @@ -31,6 +31,7 @@ #include #include +char *format_string(const char *buf, int cols, int depth); xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); xmlNode *add_key_data_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); @@ -47,7 +48,7 @@ void free_dictionary(char **dictionary); enum { BPLIST_TRUE = 0x08, BPLIST_FALSE = 0x09, - BPLIST_FILL = 0x0F, /* will be used for length grabbing */ + BPLIST_FILL = 0x0F, /* will be used for length grabbing */ BPLIST_INT = 0x10, BPLIST_REAL = 0x20, BPLIST_DATE = 0x33, @@ -62,15 +63,17 @@ enum { }; typedef struct _bplist_node { - struct _bplist_node *next, **subnodes; // subnodes is for arrays, dicts and (potentially) sets. + struct _bplist_node *next, **subnodes; // subnodes is for arrays, dicts and (potentially) sets. uint64_t length, intval64; - uint32_t intval32; // length = subnodes + uint32_t intval32; // length = subnodes uint16_t intval16; uint8_t intval8; - uint8_t type, *indexes; // indexes for array-types; essentially specify the order in which to access for key => value pairs + uint8_t type, *indexes; // indexes for array-types; essentially specify the order in which to access for key => value pairs char *strval; double realval; wchar_t *unicodeval; } bplist_node; +bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position); + #endif -- cgit v1.1-32-gdbae From 5811f92943fa81b6266e0b57d95824d1efa17120 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 28 Nov 2008 23:19:17 +0100 Subject: Start an abstraction of xml and binary plist --- src/plist.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/plist.h | 35 ++++++++ 2 files changed, 314 insertions(+) diff --git a/src/plist.c b/src/plist.c index 7a09b4d..1553c1c 100644 --- a/src/plist.c +++ b/src/plist.c @@ -536,3 +536,282 @@ bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * pos root_node = nodeslist[root_object]; return root_node; } + +struct plist_data { + union { + char boolval; + uint8_t intval8; + uint16_t intval16; + uint32_t intval32; + uint64_t intval64; + float realval32; + double realval64; + char *strval; + wchar_t *unicodeval; + char *buff; + }; + int index; + plist_type type; +}; + +void plist_new_plist(plist_t* plist) +{ + if (*plist != NULL) return; + struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + data->type = PLIST_PLIST; + *plist = g_node_new (data); +} + +void plist_new_dict_in_plist(plist_t plist, dict_t* dict) +{ + if (!plist || *dict) return; + + struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + data->type = PLIST_DICT; + *dict = g_node_new (data); + g_node_append(plist, *dict); +} + +void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array) +{ +} + +void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value) +{ + if (!dict || !key || !value) return; + + struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + data->type = PLIST_KEY; + data->strval = strdup(key); + GNode* keynode = g_node_new (data); + g_node_append(dict, keynode); + + //now handle value + struct plist_data* val = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + val->type = type; + + switch (type) { + case PLIST_BOOLEAN : val->boolval = *((char*)value); break; + case PLIST_UINT8 : val->intval8 = *((uint8_t*)value); break; + case PLIST_UINT16 : val->intval16 = *((uint16_t*)value); break; + case PLIST_UINT32 : val->intval32 = *((uint32_t*)value); break; + case PLIST_UINT64 : val->intval64 = *((uint64_t*)value); break; + case PLIST_FLOAT32 : val->realval32 = *((float*)value); break; + case PLIST_FLOAT64 : val->realval64 = *((double*)value); break; + case PLIST_STRING : val->strval = strdup((char*) value); break; + case PLIST_UNICODE : val->unicodeval = wcsdup((wchar_t*) value); break; + case PLIST_DATA : val->buff = strdup((char*) value); break; + case PLIST_ARRAY : + case PLIST_DICT : + case PLIST_DATE : + case PLIST_PLIST : + default: + break; + } + GNode* valnode = g_node_new (val); + g_node_append(dict, valnode); +} + +void plist_free(plist_t plist) +{ + g_node_destroy(plist); +} + +void node_to_xml (GNode *node, gpointer data) +{ + if (!node) return; + + struct plist_data* node_data = (struct plist_data*)node->data; + + xmlNodePtr child_node = NULL; + char isStruct = FALSE; + + gchar* tag = NULL; + gchar* val = NULL; + + switch (node_data->type) { + case PLIST_BOOLEAN : + { + if (node_data->boolval) + tag = "true"; + else + tag = "false"; + } + break; + + case PLIST_UINT8 : + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval8); + break; + + case PLIST_UINT16 : + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval16); + break; + + case PLIST_UINT32 : + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval32); + break; + + case PLIST_UINT64 : + tag = "integer"; + val = g_strdup_printf("%lu", (long unsigned int)node_data->intval64); + break; + + case PLIST_FLOAT32 : + tag = "real"; + val = g_strdup_printf("%f", node_data->realval32); + break; + + case PLIST_FLOAT64 : + tag = "real"; + val = g_strdup_printf("%Lf", (long double)node_data->intval64); + break; + + case PLIST_STRING : + tag = "string"; + val = g_strdup(node_data->strval); + break; + + case PLIST_UNICODE : + tag = "string"; + val = g_strdup((gchar*)node_data->unicodeval); + break; + + case PLIST_KEY : + tag = "key"; + val = g_strdup((gchar*)node_data->strval); + break; + + case PLIST_DATA : + tag = "data"; + val = format_string(node_data->buff, 60, 0); + break; + case PLIST_ARRAY : + tag = "array"; + isStruct = TRUE; + break; + case PLIST_DICT : + tag = "dict"; + isStruct = TRUE; + break; + case PLIST_PLIST : + tag = "plist"; + isStruct = TRUE; + break; + case PLIST_DATE : //TODO : handle date tag + default: + break; + } + return; + + child_node = xmlNewChild(data, NULL, tag, val); + gfree(val); + + if (isStruct) + g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, child_node); + + return; +} + +void xml_to_node (xmlNodePtr xml_node, GNode *plist_node) +{ + xmlNodePtr node = NULL; + struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + GNode* subnode = g_node_new (data); + g_node_append(plist_node, subnode); + + for (node = xml_node->children; node; node = node->next) { + + if (!xmlStrcmp(node->name, "true")) { + data->boolval = 1; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "false")) { + data->boolval = 0; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "integer")) { + char* strval = xmlNodeGetContent(node); + data->intval64 = atoi(strval); + data->type = PLIST_UINT64; + continue; + } + + if (!xmlStrcmp(node->name, "real")){ + char* strval = xmlNodeGetContent(node); + data->realval64 = atof(strval); + data->type = PLIST_FLOAT64; + continue; + } + + if (!xmlStrcmp(node->name, "date")) + continue;//TODO : handle date tag + + if (!xmlStrcmp(node->name, "string")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_STRING; + continue; + } + + if (!xmlStrcmp(node->name, "key")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_KEY; + continue; + } + + if (!xmlStrcmp(node->name, "data")) { + data->buff = strdup(xmlNodeGetContent(node)); + data->type = PLIST_DATA; + continue; + } + + if (!xmlStrcmp(node->name, "array")) { + data->type = PLIST_ARRAY; + xml_to_node (node, subnode); + continue; + } + + if (!xmlStrcmp(node->name, "dict")) { + data->type = PLIST_DICT; + xml_to_node (node, subnode); + continue; + } + } +} + +void plist_to_xml(plist_t plist, char** plist_xml) +{ + if (!plist || !plist_xml || *plist_xml) return; + xmlDocPtr plist_doc = new_plist(); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, root_node); + int size = 0; + xmlDocDumpMemory (plist_doc, (xmlChar**)plist_xml, &size); +} + + +void plist_to_bin(plist_t plist, char** plist_bin) +{ +} + +void xml_to_plist(const char* plist_xml, plist_t* plist) +{ + xmlDocPtr plist_doc = xmlReadMemory(plist_xml, strlen(plist_xml), NULL, NULL, 0); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + + struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + *plist = g_node_new (data); + data->type = PLIST_PLIST; + xml_to_node (root_node, *plist); + +} + +void bin_to_plist(const char* plist_bin, plist_t* plist) +{ +} diff --git a/src/plist.h b/src/plist.h index 5f31281..4586d6f 100644 --- a/src/plist.h +++ b/src/plist.h @@ -30,6 +30,7 @@ #include #include #include +#include char *format_string(const char *buf, int cols, int depth); xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); @@ -76,4 +77,38 @@ typedef struct _bplist_node { bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position); +typedef enum { + PLIST_BOOLEAN, + PLIST_UINT8, + PLIST_UINT16, + PLIST_UINT32, + PLIST_UINT64, + PLIST_FLOAT32, + PLIST_FLOAT64, + PLIST_STRING, + PLIST_UNICODE, + PLIST_ARRAY, + PLIST_DICT, + PLIST_DATE, + PLIST_DATA, + PLIST_PLIST, + PLIST_KEY, +} plist_type; + + +typedef GNode *plist_t; +typedef GNode *dict_t; +typedef GNode *array_t; + +void plist_new_plist(plist_t* plist); +void plist_new_dict_in_plist(plist_t plist, dict_t* dict); +void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array); +void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value); +void plist_free(plist_t plist); + +void plist_to_xml(plist_t plist, char** plist_xml); +void plist_to_bin(plist_t plist, char** plist_bin); + +void xml_to_plist(const char* plist_xml, plist_t* plist); +void bin_to_plist(const char* plist_bin, plist_t* plist); #endif -- cgit v1.1-32-gdbae From 831ee461bd03ad809f73b34dc5205d296158a969 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 30 Nov 2008 11:05:51 +0100 Subject: use vfprintf instead of fprintf since we use va_list as argument --- src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 049777a..ceb1f5d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -46,7 +46,7 @@ void log_debug_msg(const char *format, ...) va_start(args, format); if (toto_debug) - fprintf(stderr, format, args); + vfprintf(stderr, format, args); va_end(args); -- cgit v1.1-32-gdbae From 889cb32a1231c41762d7e2bbe6c891bd3a6c9a7d Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 30 Nov 2008 16:36:18 +0100 Subject: Continue abstraction of xml and binary plist. --- dev/plutil.c | 87 +------ src/plist.c | 799 ++++++++++++++++++++++++++++++++--------------------------- src/plist.h | 48 +--- 3 files changed, 451 insertions(+), 483 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index d1c3ddd..d1f1cd4 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -10,85 +10,6 @@ #include #include -void print_nodes(bplist_node * root_node) -{ - // Yay, great. Let's print the list of nodes recursively... - int i = 0; - if (!root_node) - return; // or not, because the programmer's stupid. - - switch (root_node->type) { - case BPLIST_DICT: - printf("Dictionary node.\nLength %lu\n", (long unsigned int) root_node->length); - for (i = 0; i < (root_node->length * 2); i += 2) { - // HI! - printf("Key: "); - print_nodes(root_node->subnodes[i]); - printf("Value: "); - print_nodes(root_node->subnodes[i + 1]); - } - printf("End dictionary node.\n\n"); - break; - - case BPLIST_ARRAY: - printf("Array node.\n"); - for (i = 0; i < root_node->length; i++) { - printf("\tElement %i: ", i); - print_nodes(root_node->subnodes[i]); - } - break; - - case BPLIST_INT: - if (root_node->length == sizeof(uint8_t)) { - printf("Integer: %i\n", root_node->intval8); - } else if (root_node->length == sizeof(uint16_t)) { - printf("Integer: %i\n", root_node->intval16); - } else if (root_node->length == sizeof(uint32_t)) { - printf("Integer: %i\n", root_node->intval32); - } - break; - - case BPLIST_STRING: - printf("String: "); - fwrite(root_node->strval, sizeof(char), root_node->length, stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_DATA: - printf("Data: "); - char *data = g_base64_encode(root_node->strval, root_node->length); - fwrite(format_string(data, 60, 0), sizeof(char), strlen(data), stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_UNICODE: - printf("Unicode data, may appear crappy: "); - fwrite(root_node->unicodeval, sizeof(wchar_t), root_node->length, stdout); - fflush(stdout); - printf("\n"); - break; - - case BPLIST_TRUE: - printf("True.\n"); - break; - - case BPLIST_FALSE: - printf("False.\n"); - break; - - case BPLIST_REAL: - case BPLIST_DATE: - printf("Real(?): %f\n", root_node->realval); - break; - - default: - printf("oops\nType set to %x and length is %lu\n", root_node->type, (long unsigned int) root_node->length); - break; - } -} - int main(int argc, char *argv[]) { struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); @@ -117,15 +38,17 @@ int main(int argc, char *argv[]) fclose(bplist); printf("or here?\n"); // bplist_entire contains our stuff - bplist_node *root_node; - root_node = parse_nodes(bplist_entire, filestats->st_size, &position); + plist_t root_node = NULL; + bin_to_plist(bplist_entire, filestats->st_size, &root_node); printf("plutil debug mode\n\n"); printf("file size %i\n\n", (int) filestats->st_size); if (!root_node) { printf("Invalid binary plist (or some other error occurred.)\n"); return 0; } - print_nodes(root_node); + char *plist_xml = NULL; + plist_to_xml(root_node, &plist_xml); + printf("%s\n", plist_xml); return 0; } diff --git a/src/plist.c b/src/plist.c index 1553c1c..377646d 100644 --- a/src/plist.c +++ b/src/plist.c @@ -25,6 +25,7 @@ #include #include "utils.h" #include "plist.h" +#include const char *plist_base = "\n\ @@ -285,147 +286,7 @@ void byte_convert(char *address, size_t size) } } -bplist_node *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size) -{ - if (!position || !bpbuffer || !bplength) - return NULL; - - uint8_t modifier = 0; - bplist_node *new_node = (bplist_node *) malloc(sizeof(bplist_node)); - bplist_node *length_stupidity = NULL; - memset(new_node, 0, sizeof(bplist_node)); // initialize the new struct - - int myPos = *position; - if (myPos == bplength || (myPos + 1) == bplength) { - free(new_node); - return NULL; - } // end of string - - uint32_t length = 0; - if (!myPos) { - if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { - return NULL; // badness! - } - myPos += strlen("bplist00"); - } - // Get the node's type. - if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real - // better handling of date; basically interpret as real or double - new_node->type = BPLIST_DATE; - new_node->length = 8; // always 8 for "date" (Apple intended it, not me) - myPos++; - memcpy(&new_node->realval, bpbuffer + myPos, sizeof(new_node->realval)); - byte_convert((char *) &new_node->realval, sizeof(new_node->realval)); - myPos += new_node->length; - *position = myPos; - return new_node; - } - - new_node->type = bpbuffer[myPos] & BPLIST_MASK; - new_node->length = bpbuffer[myPos] & BPLIST_FILL; - if (!new_node->type) { - // what? check if it's a boolean. - if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) { - // okay, so it is. Carry on. - new_node->type = bpbuffer[myPos]; - new_node->length = 0; - } else { - // er, what? we have a bad type here. Return NULL. - free(new_node); - //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); - return NULL; - } - } - - myPos++; // puts us in the data. - if (new_node->length == BPLIST_FILL) { // Data happens to contain length... - // what? you're going to make me parse an int for the length. You suck. - *position = myPos; - length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); - switch (length_stupidity->length) { - case sizeof(uint8_t): - new_node->length = length_stupidity->intval8; - break; - case sizeof(uint16_t): - new_node->length = length_stupidity->intval16; - break; - case sizeof(uint32_t): - new_node->length = length_stupidity->intval32; - break; - case sizeof(uint64_t): - new_node->length = length_stupidity->intval64; - break; - default: - free(new_node); - free(length_stupidity); - return NULL; - } - // There, we have our fucking length now. - *position = myPos; - free(length_stupidity); // cleanup - } - // Now we're in the data. - // Error-checking sorta - if ((myPos + new_node->length) >= bplength) { - new_node->length = bplength - myPos; // truncate the object - } - // And now for the greatest show on earth: the giant fucking switch statement. - switch (new_node->type) { - case BPLIST_INT: - new_node->length = uipow(2, new_node->length); // make length less misleading - switch (new_node->length) { - case sizeof(uint8_t): - new_node->intval8 = bpbuffer[myPos]; - break; - case sizeof(uint16_t): - memcpy(&new_node->intval16, bpbuffer + myPos, sizeof(uint16_t)); - new_node->intval16 = ntohs(new_node->intval16); - break; - case sizeof(uint32_t): - memcpy(&new_node->intval32, bpbuffer + myPos, sizeof(uint32_t)); - new_node->intval32 = ntohl(new_node->intval32); - break; - case sizeof(uint64_t): - memcpy(&new_node->intval64, bpbuffer + myPos, sizeof(uint64_t)); - byte_convert((char *) &new_node->intval64, sizeof(uint64_t)); - break; - default: - free(new_node); - printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) new_node->length); - printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); - return NULL; - } - break; - case BPLIST_REAL: - new_node->length = uipow(2, new_node->length); - memcpy(&new_node->realval, bpbuffer + myPos, new_node->length); // XXX: probable buffer overflow here - //new_node->realval = bpbuffer[myPos]; // why not - byte_convert((char *) &new_node->realval, sizeof(double)); - break; - - case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ - new_node->length = new_node->length * 2; // dicts lie - case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ - new_node->intval8 = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. - case BPLIST_STRING: - case BPLIST_DATA: - default: /* made to hold raw data. */ - modifier = (new_node->intval8 > 0) ? new_node->intval8 : 1; - new_node->strval = (char *) malloc(sizeof(char) * (new_node->length * modifier)); - memcpy(new_node->strval, bpbuffer + myPos, (new_node->length * modifier)); - break; - - case BPLIST_UNICODE: - new_node->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * new_node->length); - memcpy(new_node->unicodeval, bpbuffer + myPos, new_node->length); - break; - } - - myPos += new_node->length; - *position = myPos; - return new_node; -} void print_bytes(char *val, size_t size) { @@ -435,180 +296,123 @@ void print_bytes(char *val, size_t size) } } -bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position) -{ - bplist_node **nodeslist = NULL, **newaddr = NULL; - bplist_node *new_node = NULL, *root_node = NULL; - - uint32_t nodeslength = 0; - uint8_t offset_size = 0, dict_param_size = 0; - offset_size = bpbuffer[bplength - 26]; - dict_param_size = bpbuffer[bplength - 25]; - uint64_t current_offset = 0; - //uint64_t num_objects = *(bpbuffer+(bplength-24)), root_object = *(bpbuffer+(bplength-16)), offset_table_index = *(bpbuffer+(bplength-8)); - uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; - memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t)); - memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t)); - memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t)); - byte_convert((char *) &num_objects, sizeof(uint64_t)); - byte_convert((char *) &root_object, sizeof(uint64_t)); - byte_convert((char *) &offset_table_index, sizeof(uint64_t)); - - log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]); - log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]); - log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24)); - log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16)); - log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8)); - log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); - - int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; - uint32_t index1 = 0, index2 = 0; - - nodeslist = (bplist_node **) malloc(sizeof(bplist_node *) * num_objects); - if (!nodeslist) - return NULL; - - for (i = 0; i < num_objects; i++) { - memcpy(¤t_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size); - //current_offset = (offset_size == 2) ? ntohs(current_offset) : (offset_size == 4) ? ntohl(current_offset) : current_offset; - //if (offset_size == 8) byte_convert(¤t_offset, 8); - byte_convert((char *) ¤t_offset, - (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); - log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); - nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size); - log_debug_msg("parse_nodes: parse_raw_node done\n"); - } - - - for (i = 0; i < num_objects; i++) { - // set elements for dicts and arrays and leave the rest alone - log_debug_msg("parse_nodes: on node %i\n", i); - switch (nodeslist[i]->type) { - case BPLIST_DICT: - log_debug_msg("parse_nodes: dictionary found\n"); - nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length); - for (j = 0; j < (nodeslist[i]->length / 2); j++) { - str_i = j * nodeslist[i]->intval8; - str_j = (j + (nodeslist[i]->length / 2)) * nodeslist[i]->intval8; - - memcpy(&index1, nodeslist[i]->strval + str_i, nodeslist[i]->intval8); - memcpy(&index2, nodeslist[i]->strval + str_j, nodeslist[i]->intval8); - //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; - //index2 = (dict_param_size == 1) ? index2 : (dict_param_size == 2) ? ntohs(index2) : (dict_param_size == 4) ? ntohl(index2) : index2; - byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); - byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); - //printf("parse_nodes: key index %i value %i\n", index1, index2); - //printf("parse_nodes: key type %x and length %i\n", nodeslist[index1]->type, nodeslist[index1]->length); - //printf("parse_nodes: value type %x and length %i\n", nodeslist[index2]->type, nodeslist[index2]->length); - nodeslist[i]->subnodes[k++] = nodeslist[index1]; - nodeslist[i]->subnodes[k++] = nodeslist[index2]; - } - - nodeslist[i]->length = nodeslist[i]->length / 2; - free(nodeslist[i]->strval); - k = 0; - break; - - case BPLIST_ARRAY: - log_debug_msg("parse_nodes: array found\n"); - nodeslist[i]->subnodes = (bplist_node **) malloc(sizeof(bplist_node) * nodeslist[i]->length); // memory allocation helps a lot when storing data - - for (j = 0; j < nodeslist[i]->length; j++) { - log_debug_msg("parse_nodes: array index %i\n", j); - str_j = j * nodeslist[i]->intval8; - //index1 = nodeslist[i]->strval[j]; - memcpy(&index1, nodeslist[i]->strval + str_j, nodeslist[i]->intval8); - log_debug_msg("parse_nodes: post-memcpy\n"); - //index1 = (dict_param_size == 1) ? index1 : (dict_param_size == 2) ? ntohs(index1) : (dict_param_size == 4) ? ntohl(index1) : index1; - byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); - log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); - nodeslist[i]->subnodes[j] = nodeslist[index1]; - log_debug_msg("parse_nodes: post-assignment\n"); - } - free(nodeslist[i]->strval); - break; - default: - //printf("lol... type %x\n", nodeslist[i]->type); - break; - } // those are the only two we need to correct for. - } - root_node = nodeslist[root_object]; - return root_node; -} struct plist_data { union { - char boolval; - uint8_t intval8; + char boolval; + uint8_t intval8; uint16_t intval16; uint32_t intval32; uint64_t intval64; - float realval32; - double realval64; - char *strval; + float realval32; + double realval64; + char *strval; wchar_t *unicodeval; - char *buff; + struct { + char *buff; + uint8_t ref_size; + }; }; - int index; + uint64_t length; plist_type type; }; -void plist_new_plist(plist_t* plist) +enum { + BPLIST_TRUE = 0x08, + BPLIST_FALSE = 0x09, + BPLIST_FILL = 0x0F, /* will be used for length grabbing */ + BPLIST_INT = 0x10, + BPLIST_REAL = 0x20, + BPLIST_DATE = 0x33, + BPLIST_DATA = 0x40, + BPLIST_STRING = 0x50, + BPLIST_UNICODE = 0x60, + BPLIST_UID = 0x70, + BPLIST_ARRAY = 0xA0, + BPLIST_SET = 0xC0, + BPLIST_DICT = 0xD0, + BPLIST_MASK = 0xF0 +}; + +void plist_new_plist(plist_t * plist) { - if (*plist != NULL) return; - struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + if (*plist != NULL) + return; + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); data->type = PLIST_PLIST; - *plist = g_node_new (data); + *plist = g_node_new(data); } -void plist_new_dict_in_plist(plist_t plist, dict_t* dict) +void plist_new_dict_in_plist(plist_t plist, dict_t * dict) { - if (!plist || *dict) return; + if (!plist || *dict) + return; - struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); data->type = PLIST_DICT; - *dict = g_node_new (data); + *dict = g_node_new(data); g_node_append(plist, *dict); } -void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array) +void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array) { } -void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value) +void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value) { - if (!dict || !key || !value) return; + if (!dict || !key || !value) + return; - struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); data->type = PLIST_KEY; data->strval = strdup(key); - GNode* keynode = g_node_new (data); + GNode *keynode = g_node_new(data); g_node_append(dict, keynode); //now handle value - struct plist_data* val = (struct plist_data*)calloc(sizeof(struct plist_data), 1); + struct plist_data *val = (struct plist_data *) calloc(sizeof(struct plist_data), 1); val->type = type; switch (type) { - case PLIST_BOOLEAN : val->boolval = *((char*)value); break; - case PLIST_UINT8 : val->intval8 = *((uint8_t*)value); break; - case PLIST_UINT16 : val->intval16 = *((uint16_t*)value); break; - case PLIST_UINT32 : val->intval32 = *((uint32_t*)value); break; - case PLIST_UINT64 : val->intval64 = *((uint64_t*)value); break; - case PLIST_FLOAT32 : val->realval32 = *((float*)value); break; - case PLIST_FLOAT64 : val->realval64 = *((double*)value); break; - case PLIST_STRING : val->strval = strdup((char*) value); break; - case PLIST_UNICODE : val->unicodeval = wcsdup((wchar_t*) value); break; - case PLIST_DATA : val->buff = strdup((char*) value); break; - case PLIST_ARRAY : - case PLIST_DICT : - case PLIST_DATE : - case PLIST_PLIST : - default: - break; + case PLIST_BOOLEAN: + val->boolval = *((char *) value); + break; + case PLIST_UINT8: + val->intval8 = *((uint8_t *) value); + break; + case PLIST_UINT16: + val->intval16 = *((uint16_t *) value); + break; + case PLIST_UINT32: + val->intval32 = *((uint32_t *) value); + break; + case PLIST_UINT64: + val->intval64 = *((uint64_t *) value); + break; + case PLIST_FLOAT32: + val->realval32 = *((float *) value); + break; + case PLIST_FLOAT64: + val->realval64 = *((double *) value); + break; + case PLIST_STRING: + val->strval = strdup((char *) value); + break; + case PLIST_UNICODE: + val->unicodeval = wcsdup((wchar_t *) value); + break; + case PLIST_DATA: + val->buff = strdup((char *) value); + break; + case PLIST_ARRAY: + case PLIST_DICT: + case PLIST_DATE: + case PLIST_PLIST: + default: + break; } - GNode* valnode = g_node_new (val); + GNode *valnode = g_node_new(val); g_node_append(dict, valnode); } @@ -617,97 +421,98 @@ void plist_free(plist_t plist) g_node_destroy(plist); } -void node_to_xml (GNode *node, gpointer data) +void node_to_xml(GNode * node, gpointer data) { - if (!node) return; + if (!node) + return; - struct plist_data* node_data = (struct plist_data*)node->data; + struct plist_data *node_data = (struct plist_data *) node->data; xmlNodePtr child_node = NULL; char isStruct = FALSE; - gchar* tag = NULL; - gchar* val = NULL; + gchar *tag = NULL; + gchar *val = NULL; switch (node_data->type) { - case PLIST_BOOLEAN : - { + case PLIST_BOOLEAN: + { if (node_data->boolval) tag = "true"; else tag = "false"; - } - break; + } + break; - case PLIST_UINT8 : - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval8); - break; + case PLIST_UINT8: + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval8); + break; - case PLIST_UINT16 : - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval16); - break; + case PLIST_UINT16: + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval16); + break; - case PLIST_UINT32 : - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval32); - break; + case PLIST_UINT32: + tag = "integer"; + val = g_strdup_printf("%u", node_data->intval32); + break; - case PLIST_UINT64 : - tag = "integer"; - val = g_strdup_printf("%lu", (long unsigned int)node_data->intval64); - break; + case PLIST_UINT64: + tag = "integer"; + val = g_strdup_printf("%lu", (long unsigned int) node_data->intval64); + break; - case PLIST_FLOAT32 : - tag = "real"; - val = g_strdup_printf("%f", node_data->realval32); - break; + case PLIST_FLOAT32: + tag = "real"; + val = g_strdup_printf("%f", node_data->realval32); + break; - case PLIST_FLOAT64 : - tag = "real"; - val = g_strdup_printf("%Lf", (long double)node_data->intval64); - break; + case PLIST_FLOAT64: + tag = "real"; + val = g_strdup_printf("%Lf", (long double) node_data->intval64); + break; - case PLIST_STRING : - tag = "string"; - val = g_strdup(node_data->strval); - break; + case PLIST_STRING: + tag = "string"; + val = g_strdup(node_data->strval); + break; - case PLIST_UNICODE : - tag = "string"; - val = g_strdup((gchar*)node_data->unicodeval); - break; + case PLIST_UNICODE: + tag = "string"; + val = g_strdup((gchar *) node_data->unicodeval); + break; - case PLIST_KEY : - tag = "key"; - val = g_strdup((gchar*)node_data->strval); - break; + case PLIST_KEY: + tag = "key"; + val = g_strdup((gchar *) node_data->strval); + break; - case PLIST_DATA : - tag = "data"; - val = format_string(node_data->buff, 60, 0); - break; - case PLIST_ARRAY : - tag = "array"; - isStruct = TRUE; - break; - case PLIST_DICT : - tag = "dict"; - isStruct = TRUE; - break; - case PLIST_PLIST : - tag = "plist"; - isStruct = TRUE; - break; - case PLIST_DATE : //TODO : handle date tag - default: - break; + case PLIST_DATA: + tag = "data"; + val = format_string(node_data->buff, 60, 0); + break; + case PLIST_ARRAY: + tag = "array"; + isStruct = TRUE; + break; + case PLIST_DICT: + tag = "dict"; + isStruct = TRUE; + break; + case PLIST_PLIST: + tag = "plist"; + isStruct = TRUE; + break; + case PLIST_DATE: //TODO : handle date tag + default: + break; } - return; child_node = xmlNewChild(data, NULL, tag, val); - gfree(val); + xmlNodeAddContent(child_node, "\n"); + g_free(val); if (isStruct) g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, child_node); @@ -715,11 +520,11 @@ void node_to_xml (GNode *node, gpointer data) return; } -void xml_to_node (xmlNodePtr xml_node, GNode *plist_node) +void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) { xmlNodePtr node = NULL; - struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); - GNode* subnode = g_node_new (data); + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + GNode *subnode = g_node_new(data); g_node_append(plist_node, subnode); for (node = xml_node->children; node; node = node->next) { @@ -737,21 +542,21 @@ void xml_to_node (xmlNodePtr xml_node, GNode *plist_node) } if (!xmlStrcmp(node->name, "integer")) { - char* strval = xmlNodeGetContent(node); + char *strval = xmlNodeGetContent(node); data->intval64 = atoi(strval); data->type = PLIST_UINT64; continue; } - if (!xmlStrcmp(node->name, "real")){ - char* strval = xmlNodeGetContent(node); + if (!xmlStrcmp(node->name, "real")) { + char *strval = xmlNodeGetContent(node); data->realval64 = atof(strval); data->type = PLIST_FLOAT64; continue; } if (!xmlStrcmp(node->name, "date")) - continue;//TODO : handle date tag + continue; //TODO : handle date tag if (!xmlStrcmp(node->name, "string")) { data->strval = strdup(xmlNodeGetContent(node)); @@ -773,45 +578,315 @@ void xml_to_node (xmlNodePtr xml_node, GNode *plist_node) if (!xmlStrcmp(node->name, "array")) { data->type = PLIST_ARRAY; - xml_to_node (node, subnode); + xml_to_node(node, subnode); continue; } if (!xmlStrcmp(node->name, "dict")) { data->type = PLIST_DICT; - xml_to_node (node, subnode); + xml_to_node(node, subnode); continue; } } } -void plist_to_xml(plist_t plist, char** plist_xml) +void plist_to_xml(plist_t plist, char **plist_xml) { - if (!plist || !plist_xml || *plist_xml) return; + if (!plist || !plist_xml || *plist_xml) + return; xmlDocPtr plist_doc = new_plist(); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, root_node); int size = 0; - xmlDocDumpMemory (plist_doc, (xmlChar**)plist_xml, &size); + xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, &size); } +GNode *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size) +{ + if (!position || !bpbuffer || !bplength) + return NULL; + + uint8_t modifier = 0; + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + GNode *new_node = g_node_new(data); + GNode *length_stupidity = NULL; + + int myPos = *position; + if (myPos == bplength || (myPos + 1) == bplength) { + g_node_destroy(new_node); + return NULL; + } // end of string + + uint32_t length = 0; + if (!myPos) { + if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { + return NULL; // badness! + } + myPos += strlen("bplist00"); + } + // Get the node's type. + if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real + // better handling of date; basically interpret as real or double + data->type = BPLIST_DATE; + length = 8; // always 8 for "date" (Apple intended it, not me) + myPos++; + memcpy(&data->realval64, bpbuffer + myPos, sizeof(data->realval64)); + byte_convert((char *) &data->realval64, sizeof(data->realval64)); + myPos += length; + *position = myPos; + return new_node; + } + + int type = bpbuffer[myPos] & BPLIST_MASK; + data->length = bpbuffer[myPos] & BPLIST_FILL; + + if (!type) { + // what? check if it's a boolean. + if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) { + // okay, so it is. Carry on. + data->type = PLIST_BOOLEAN; + data->boolval = TRUE; + data->length = 0; + } else { + // er, what? we have a bad type here. Return NULL. + g_node_destroy(new_node); + //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); + return NULL; + } + } + + myPos++; // puts us in the data. + if (length == BPLIST_FILL) { // Data happens to contain length... + // what? you're going to make me parse an int for the length. You suck. + *position = myPos; + length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); + switch (((struct plist_data *) length_stupidity->data)->type) { + case PLIST_UINT8: + data->length = ((struct plist_data *) length_stupidity->data)->intval8; + break; + case PLIST_UINT16: + data->length = ((struct plist_data *) length_stupidity->data)->intval16; + break; + case PLIST_UINT32: + data->length = ((struct plist_data *) length_stupidity->data)->intval32; + break; + case PLIST_UINT64: + data->length = ((struct plist_data *) length_stupidity->data)->intval64; + break; + default: + g_node_destroy(new_node); + g_node_destroy(length_stupidity); + return NULL; + } + // There, we have our fucking length now. + *position = myPos; + g_node_destroy(length_stupidity); // cleanup + } + // Now we're in the data. + // Error-checking sorta + if ((myPos + data->length) >= bplength) { + data->length = bplength - myPos; // truncate the object + } + // And now for the greatest show on earth: the giant fucking switch statement. + switch (type) { + case BPLIST_INT: + data->length = uipow(2, data->length); // make length less misleading + switch (data->length) { + case sizeof(uint8_t): + data->type = PLIST_UINT8; + data->intval8 = bpbuffer[myPos]; + break; + case sizeof(uint16_t): + data->type = PLIST_UINT16; + memcpy(&data->intval16, bpbuffer + myPos, sizeof(uint16_t)); + data->intval16 = ntohs(data->intval16); + break; + case sizeof(uint32_t): + data->type = PLIST_UINT32; + memcpy(&data->intval32, bpbuffer + myPos, sizeof(uint32_t)); + data->intval32 = ntohl(data->intval32); + break; + case sizeof(uint64_t): + data->type = PLIST_UINT64; + memcpy(&data->intval64, bpbuffer + myPos, sizeof(uint64_t)); + byte_convert((char *) &data->intval64, sizeof(uint64_t)); + break; + default: + g_node_destroy(new_node); + printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) length); + printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); + return NULL; + } + break; + + case BPLIST_REAL: + data->length = uipow(2, data->length); + switch (data->length) { + case sizeof(float): + data->type = PLIST_FLOAT32; + memcpy(&data->realval32, bpbuffer + myPos, data->length); + byte_convert((char *) &data->realval32, sizeof(float)); //necessary ?? + break; + case sizeof(double): + data->type = PLIST_FLOAT64; + memcpy(&data->realval64, bpbuffer + myPos, data->length); + byte_convert((char *) &data->realval64, sizeof(double)); + break; + default: + g_node_destroy(new_node); + printf("parse_raw_node: lol: invalid real: size given %lu\n", (long unsigned int) length); + printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); + return NULL; + } + break; + + case BPLIST_STRING: + data->type = PLIST_STRING; + data->strval = (char *) malloc(sizeof(char) * data->length); + memcpy(data->strval, bpbuffer + myPos, data->length); + break; + + case BPLIST_UNICODE: + data->type = PLIST_UNICODE; + data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * data->length); + memcpy(data->unicodeval, bpbuffer + myPos, data->length); + break; + + case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ + data->length = data->length * 2; // dicts lie + data->type = PLIST_DICT; + + case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ + data->ref_size = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. + if (data->type == 0) + data->type = PLIST_ARRAY; + case BPLIST_DATA: + if (data->type == 0) + data->type = PLIST_DATA; + default: /* made to hold raw data. */ + modifier = (data->ref_size > 0) ? data->ref_size : 1; + data->buff = (char *) malloc(sizeof(char) * (data->length * modifier)); + memcpy(data->buff, bpbuffer + myPos, (data->length * modifier)); + break; + + } + + myPos += data->length; + *position = myPos; + return new_node; +} + +plist_t parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position) +{ + plist_t *nodeslist = NULL, *newaddr = NULL; + plist_t new_node = NULL, root_node = NULL; + + uint32_t nodeslength = 0; + uint8_t offset_size = 0, dict_param_size = 0; + offset_size = bpbuffer[bplength - 26]; + dict_param_size = bpbuffer[bplength - 25]; + uint64_t current_offset = 0; + uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; + memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t)); + memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t)); + memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t)); + byte_convert((char *) &num_objects, sizeof(uint64_t)); + byte_convert((char *) &root_object, sizeof(uint64_t)); + byte_convert((char *) &offset_table_index, sizeof(uint64_t)); + + log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]); + log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]); + log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24)); + log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16)); + log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8)); + log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); + + int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; + uint32_t index1 = 0, index2 = 0; + + nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); + if (!nodeslist) + return NULL; + + for (i = 0; i < num_objects; i++) { + memcpy(¤t_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size); + byte_convert((char *) ¤t_offset, + (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); + log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); + nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size); + log_debug_msg("parse_nodes: parse_raw_node done\n"); + } + + + for (i = 0; i < num_objects; i++) { + // set elements for dicts and arrays and leave the rest alone + log_debug_msg("parse_nodes: on node %i\n", i); + struct plist_data *data = (struct plist_data *) nodeslist[i]->data; + + switch (data->type) { + case PLIST_DICT: + log_debug_msg("parse_nodes: dictionary found\n"); + for (j = 0; j < (data->length / 2); j++) { + str_i = j * data->ref_size; + str_j = (j + (data->length / 2)) * data->ref_size; + + memcpy(&index1, data->buff + str_i, data->ref_size); + memcpy(&index2, data->buff + str_j, data->ref_size); + + byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); + byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); + + g_node_append(nodeslist[i], nodeslist[index1]); + g_node_append(nodeslist[i], nodeslist[index2]); + } + + data->length = data->length / 2; + free(data->buff); + k = 0; + break; + + case PLIST_ARRAY: + log_debug_msg("parse_nodes: array found\n"); + for (j = 0; j < data->length; j++) { + log_debug_msg("parse_nodes: array index %i\n", j); + str_j = j * data->ref_size; + memcpy(&index1, data->buff + str_j, data->ref_size); + log_debug_msg("parse_nodes: post-memcpy\n"); + byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); + log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); + g_node_append(nodeslist[i], nodeslist[index1]); + log_debug_msg("parse_nodes: post-assignment\n"); + } + free(data->buff); + break; + default: + //printf("lol... type %x\n", nodeslist[i]->type); + break; + } // those are the only two we need to correct for. + } + + root_node = nodeslist[root_object]; + return root_node; +} -void plist_to_bin(plist_t plist, char** plist_bin) +void plist_to_bin(plist_t plist, char **plist_bin, int *length) { } -void xml_to_plist(const char* plist_xml, plist_t* plist) +void xml_to_plist(const char *plist_xml, plist_t * plist) { xmlDocPtr plist_doc = xmlReadMemory(plist_xml, strlen(plist_xml), NULL, NULL, 0); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - struct plist_data* data = (struct plist_data*)calloc(sizeof(struct plist_data), 1); - *plist = g_node_new (data); + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + *plist = g_node_new(data); data->type = PLIST_PLIST; - xml_to_node (root_node, *plist); + xml_to_node(root_node, *plist); } -void bin_to_plist(const char* plist_bin, plist_t* plist) +void bin_to_plist(const char *plist_bin, int length, plist_t * plist) { + uint32_t pos = 0; + *plist = parse_nodes(plist_bin, length, &pos); } diff --git a/src/plist.h b/src/plist.h index 4586d6f..1ca55f9 100644 --- a/src/plist.h +++ b/src/plist.h @@ -46,38 +46,8 @@ void free_dictionary(char **dictionary); /* Binary plist stuff */ -enum { - BPLIST_TRUE = 0x08, - BPLIST_FALSE = 0x09, - BPLIST_FILL = 0x0F, /* will be used for length grabbing */ - BPLIST_INT = 0x10, - BPLIST_REAL = 0x20, - BPLIST_DATE = 0x33, - BPLIST_DATA = 0x40, - BPLIST_STRING = 0x50, - BPLIST_UNICODE = 0x60, - BPLIST_UID = 0x70, - BPLIST_ARRAY = 0xA0, - BPLIST_SET = 0xC0, - BPLIST_DICT = 0xD0, - BPLIST_MASK = 0xF0 -}; -typedef struct _bplist_node { - struct _bplist_node *next, **subnodes; // subnodes is for arrays, dicts and (potentially) sets. - uint64_t length, intval64; - uint32_t intval32; // length = subnodes - uint16_t intval16; - uint8_t intval8; - uint8_t type, *indexes; // indexes for array-types; essentially specify the order in which to access for key => value pairs - char *strval; - double realval; - wchar_t *unicodeval; -} bplist_node; - -bplist_node *parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position); - -typedef enum { +typedef enum { PLIST_BOOLEAN, PLIST_UINT8, PLIST_UINT16, @@ -100,15 +70,15 @@ typedef GNode *plist_t; typedef GNode *dict_t; typedef GNode *array_t; -void plist_new_plist(plist_t* plist); -void plist_new_dict_in_plist(plist_t plist, dict_t* dict); -void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void** values, array_t* array); -void plist_add_dict_element(dict_t dict, char* key, plist_type type, void* value); +void plist_new_plist(plist_t * plist); +void plist_new_dict_in_plist(plist_t plist, dict_t * dict); +void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array); +void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value); void plist_free(plist_t plist); -void plist_to_xml(plist_t plist, char** plist_xml); -void plist_to_bin(plist_t plist, char** plist_bin); +void plist_to_xml(plist_t plist, char **plist_xml); +void plist_to_bin(plist_t plist, char **plist_bin, int *length); -void xml_to_plist(const char* plist_xml, plist_t* plist); -void bin_to_plist(const char* plist_bin, plist_t* plist); +void xml_to_plist(const char *plist_xml, plist_t * plist); +void bin_to_plist(const char *plist_bin, int length, plist_t * plist); #endif -- cgit v1.1-32-gdbae From d560cf5a15d1aef74e95b208ed69b7d324d94354 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 30 Nov 2008 21:49:56 +0100 Subject: complete xml plist abstraction and migrate lockdownd_hello to new plist API. --- dev/plutil.c | 3 +- src/lockdown.c | 62 ++++++++++++++----------- src/plist.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++-------- src/plist.h | 12 +++-- 4 files changed, 168 insertions(+), 50 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index d1f1cd4..0e25291 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -47,7 +47,8 @@ int main(int argc, char *argv[]) return 0; } char *plist_xml = NULL; - plist_to_xml(root_node, &plist_xml); + int size = 0; + plist_to_xml(root_node, &plist_xml, &size); printf("%s\n", plist_xml); return 0; } diff --git a/src/lockdown.c b/src/lockdown.c index 6b8f298..2906fdf 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -201,49 +201,57 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) { if (!control) return IPHONE_E_INVALID_ARG; - xmlDocPtr plist = new_plist(); - xmlNode *dict, *key; - char **dictionary; + int bytes = 0, i = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + plist_t plist = NULL; + plist_new_plist(&plist); + + dict_t dict = NULL; + plist_new_dict_in_plist(plist, &dict); + + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType"); + log_debug_msg("lockdownd_hello() called\n"); - dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - key = add_key_str_dict_element(plist, dict, "Request", "QueryType", 1); - char *XML_content; - uint32_t length; + char *XML_content = NULL; + uint32_t length = 0; - xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); + plist_to_xml(plist, &XML_content, &length); + log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); ret = iphone_lckd_send(control, XML_content, length, &bytes); xmlFree(XML_content); - xmlFreeDoc(plist); + XML_content = NULL; + plist_free(plist); plist = 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, &plist); - plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); if (!plist) return IPHONE_E_PLIST_ERROR; - dict = xmlDocGetRootElement(plist); - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) - break; - } - if (!dict) - return IPHONE_E_DICT_ERROR; - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(XML_content); - for (i = 0; dictionary[i]; i += 2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { - log_debug_msg("lockdownd_hello(): success\n"); - ret = IPHONE_E_SUCCESS; - break; - } + plist_t query_node = find_query_node(plist, "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; + + get_type_and_value(result_node, &result_type, (void *) (&result_value)); + get_type_and_value(value_node, &value_type, (void *) (&value_value)); + + 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; } - free_dictionary(dictionary); return ret; } diff --git a/src/plist.c b/src/plist.c index 377646d..5b61570 100644 --- a/src/plist.c +++ b/src/plist.c @@ -286,8 +286,6 @@ void byte_convert(char *address, size_t size) } } - - void print_bytes(char *val, size_t size) { int i = 0; @@ -421,11 +419,17 @@ void plist_free(plist_t plist) g_node_destroy(plist); } -void node_to_xml(GNode * node, gpointer data) +struct xml_node { + xmlNodePtr xml; + uint32_t depth; +}; + +void node_to_xml(GNode * node, gpointer xml_struct) { if (!node) return; + struct xml_node *xstruct = (struct xml_node *) xml_struct; struct plist_data *node_data = (struct plist_data *) node->data; xmlNodePtr child_node = NULL; @@ -510,12 +514,31 @@ void node_to_xml(GNode * node, gpointer data) break; } - child_node = xmlNewChild(data, NULL, tag, val); - xmlNodeAddContent(child_node, "\n"); + int i = 0; + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(xstruct->xml, "\t"); + } + child_node = xmlNewChild(xstruct->xml, NULL, tag, val); + xmlNodeAddContent(xstruct->xml, "\n"); g_free(val); - if (isStruct) - g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, child_node); + //add return for structured types + if (node_data->type == PLIST_ARRAY || + node_data->type == PLIST_DICT || node_data->type == PLIST_DATA || node_data->type == PLIST_PLIST) + xmlNodeAddContent(child_node, "\n"); + + if (isStruct) { + struct xml_node child = { child_node, xstruct->depth + 1 }; + g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); + } + //fix indent for structured types + if (node_data->type == PLIST_ARRAY || + node_data->type == PLIST_DICT || node_data->type == PLIST_DATA || node_data->type == PLIST_PLIST) { + + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(child_node, "\t"); + } + } return; } @@ -523,12 +546,18 @@ void node_to_xml(GNode * node, gpointer data) void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) { xmlNodePtr node = NULL; - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - GNode *subnode = g_node_new(data); - g_node_append(plist_node, subnode); for (node = xml_node->children; node; node = node->next) { + while (node && !xmlStrcmp(node->name, "text")) + node = node->next; + if (!node) + break; + + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + GNode *subnode = g_node_new(data); + g_node_append(plist_node, subnode); + if (!xmlStrcmp(node->name, "true")) { data->boolval = 1; data->type = PLIST_BOOLEAN; @@ -590,15 +619,15 @@ void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) } } -void plist_to_xml(plist_t plist, char **plist_xml) +void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) { if (!plist || !plist_xml || *plist_xml) return; xmlDocPtr plist_doc = new_plist(); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, root_node); - int size = 0; - xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, &size); + struct xml_node root = { root_node, 0 }; + g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); + xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); } GNode *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size) @@ -869,13 +898,13 @@ plist_t parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position return root_node; } -void plist_to_bin(plist_t plist, char **plist_bin, int *length) +void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) { } -void xml_to_plist(const char *plist_xml, plist_t * plist) +void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) { - xmlDocPtr plist_doc = xmlReadMemory(plist_xml, strlen(plist_xml), NULL, NULL, 0); + xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); @@ -885,8 +914,84 @@ void xml_to_plist(const char *plist_xml, plist_t * plist) } -void bin_to_plist(const char *plist_bin, int length, plist_t * plist) +void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) { uint32_t pos = 0; *plist = parse_nodes(plist_bin, length, &pos); } + + +GNode *find_query_node(plist_t plist, char *key, char *request) +{ + if (!plist) + return NULL; + + GNode *current = NULL; + for (current = plist->children; current; current = current->next) { + + struct plist_data *data = (struct plist_data *) current->data; + + if (data->type == PLIST_KEY && !strcmp(data->strval, key) && current->next) { + + data = (struct plist_data *) current->next->data; + if (data->type == PLIST_STRING && !strcmp(data->strval, request)) + return current->next; + } + if (data->type == PLIST_DICT || data->type == PLIST_ARRAY || data->type == PLIST_PLIST) { + GNode *sub = find_query_node(current, key, request); + if (sub) + return sub; + } + } + return NULL; +} + +void get_type_and_value(GNode * node, plist_type * type, void *value) +{ + if (!node) + return; + + struct plist_data *data = (struct plist_data *) node->data; + + *type = data->type; + + switch (*type) { + case PLIST_BOOLEAN: + *((char *) value) = data->boolval; + break; + case PLIST_UINT8: + *((uint8_t *) value) = data->intval8; + break; + case PLIST_UINT16: + *((uint16_t *) value) = data->intval16; + break; + case PLIST_UINT32: + *((uint32_t *) value) = data->intval32; + break; + case PLIST_UINT64: + *((uint64_t *) value) = data->intval64; + break; + case PLIST_FLOAT32: + *((float *) value) = data->realval32; + break; + case PLIST_FLOAT64: + *((double *) value) = data->realval64; + break; + case PLIST_STRING: + *((char **) value) = strdup(data->strval); + break; + case PLIST_UNICODE: + *((wchar_t **) value) = wcsdup(data->unicodeval); + break; + case PLIST_KEY: + *((char **) value) = strdup(data->strval); + break; + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + case PLIST_DATE: + case PLIST_PLIST: + default: + break; + } +} diff --git a/src/plist.h b/src/plist.h index 1ca55f9..ffc00e4 100644 --- a/src/plist.h +++ b/src/plist.h @@ -70,15 +70,19 @@ typedef GNode *plist_t; typedef GNode *dict_t; typedef GNode *array_t; + void plist_new_plist(plist_t * plist); void plist_new_dict_in_plist(plist_t plist, dict_t * dict); void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array); void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value); void plist_free(plist_t plist); -void plist_to_xml(plist_t plist, char **plist_xml); -void plist_to_bin(plist_t plist, char **plist_bin, int *length); +void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); +void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); + +void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist); +void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); -void xml_to_plist(const char *plist_xml, plist_t * plist); -void bin_to_plist(const char *plist_bin, int length, plist_t * plist); +GNode *find_query_node(plist_t plist, char *key, char *request); +void get_type_and_value(GNode * node, plist_type * type, void *value); #endif -- cgit v1.1-32-gdbae From 3d08602c6e5c86538e447fccd774a0eac0391868 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 30 Nov 2008 23:33:39 +0100 Subject: migrate lockdownd_generic_get_value to new plisy API. --- src/lockdown.c | 80 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/src/lockdown.c b/src/lockdown.c index 2906fdf..1782d45 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -267,26 +267,27 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r { if (!control || !req_key || !value || (value && *value)) return IPHONE_E_INVALID_ARG; - xmlDocPtr plist = new_plist(); - xmlNode *dict = NULL; - xmlNode *key = NULL;; - char **dictionary = NULL; + plist_t plist = NULL; + dict_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 */ - dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - key = add_key_str_dict_element(plist, dict, req_key, req_string, 1); - key = add_key_str_dict_element(plist, dict, "Request", "GetValue", 1); - xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); + plist_new_plist(&plist); + plist_new_dict_in_plist(plist, &dict); + plist_add_dict_element(dict, req_key, PLIST_STRING, (void *) req_string); + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "GetValue"); + plist_to_xml(plist, &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); xmlFree(XML_content); - xmlFreeDoc(plist); + XML_content = NULL; + plist_free(plist); plist = NULL; if (ret != IPHONE_E_SUCCESS) @@ -294,42 +295,55 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r /* 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; - plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); + xml_to_plist(XML_content, bytes, &plist); if (!plist) return IPHONE_E_PLIST_ERROR; - dict = xmlDocGetRootElement(plist); - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) - break; - } - if (!dict) - return IPHONE_E_DICT_ERROR; - /* Parse xml to check success and to find public key */ - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(XML_content); + plist_t query_node = find_query_node(plist, "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); - int success = 0; - for (i = 0; dictionary[i]; i += 2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { - success = 1; - } - if (!strcmp(dictionary[i], "Value")) { - *value = strdup(dictionary[i + 1]); - } + plist_type result_key_type; + plist_type result_value_type; + char *result_key = NULL; + char *result_value = NULL; + + get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key)); + get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + + 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 (dictionary) { - free_dictionary(dictionary); - dictionary = NULL; + if (ret != IPHONE_E_SUCCESS) { + return IPHONE_E_DICT_ERROR; } - if (success) + + 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; + + get_type_and_value(value_key_node, &value_key_type, (void *) (&value_key)); + get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value)); + + if (value_key_type == PLIST_KEY && !strcmp(result_key, "Value")) { + log_debug_msg("lockdownd_generic_get_value(): success\n"); + *value = value_value; ret = IPHONE_E_SUCCESS; + } + + plist_free(plist); + free(XML_content); return ret; } -- cgit v1.1-32-gdbae From 505c97582b53ed406169f931a49ee6f678b19b52 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 1 Dec 2008 20:25:12 +0100 Subject: continue migration to new plist API. --- src/lockdown.c | 184 +++++++++++++++++++++++++++------------------------------ src/plist.c | 67 +++++++++++++++++++++ src/plist.h | 1 + 3 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/lockdown.c b/src/lockdown.c index 1782d45..3d39fbd 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -91,7 +91,6 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone) return control; } - /** Closes the lockdownd client and does the necessary housekeeping. * * @param control The lockdown client @@ -436,10 +435,9 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, char *host_id) { iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - xmlDocPtr plist = new_plist(); - xmlNode *dict = NULL; - xmlNode *dictRecord = NULL; - char **dictionary = NULL; + plist_t plist = NULL; + dict_t dict = NULL; + dict_t dict_record = NULL; int bytes = 0, i = 0; char *XML_content = NULL; uint32_t length = 0; @@ -462,24 +460,23 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch } /* Setup Pair request plist */ - dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - dictRecord = add_key_dict_node(plist, dict, "PairRecord", "\n", 1); - //dictRecord = add_child_to_plist(plist, "dict", "\n", NULL, 1); - add_key_data_dict_element(plist, dictRecord, "DeviceCertificate", device_cert_b64, 2); - add_key_data_dict_element(plist, dictRecord, "HostCertificate", host_cert_b64, 2); - add_key_str_dict_element(plist, dictRecord, "HostID", host_id, 2); - add_key_data_dict_element(plist, dictRecord, "RootCertificate", root_cert_b64, 2); - add_key_str_dict_element(plist, dict, "Request", "Pair", 1); - - xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); - - printf("XML Pairing request : %s\n", XML_content); + plist_new_plist(&plist); + plist_new_dict_in_plist(plist, &dict); + plist_add_dict_element(dict, "PairRecord", PLIST_DICT, NULL); + dict_record = g_node_last_child(dict); + plist_add_dict_element(dict_record, "DeviceCertificate", PLIST_DATA, (void *) device_cert_b64); + plist_add_dict_element(dict_record, "HostCertificate", PLIST_DATA, (void *) host_cert_b64); + plist_add_dict_element(dict_record, "HostID", PLIST_STRING, (void *) host_id); + plist_add_dict_element(dict_record, "RootCertificate", PLIST_DATA, (void *) root_cert_b64); + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "Pair"); + plist_to_xml(plist, &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); xmlFree(XML_content); - xmlFreeDoc(plist); + plist_free(plist); plist = NULL; if (ret != IPHONE_E_SUCCESS) @@ -495,40 +492,29 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch log_debug_msg(XML_content); log_debug_msg("\n\n"); - plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); - if (!plist) { - free(public_key_b64); + xml_to_plist(XML_content, bytes, &plist); + if (!plist) return IPHONE_E_PLIST_ERROR; - } - dict = xmlDocGetRootElement(plist); - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) - break; - } - if (!dict) { - free(public_key_b64); - return IPHONE_E_DICT_ERROR; - } - /* Parse xml to check success and to find public key */ - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(XML_content); + plist_t query_node = find_query_node(plist, "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); - int success = 0; - for (i = 0; dictionary[i]; i += 2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { - success = 1; - } - } + plist_type result_key_type; + plist_type result_value_type; + char *result_key = NULL; + char *result_value = NULL; - if (dictionary) { - free_dictionary(dictionary); - dictionary = NULL; + get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key)); + get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + + 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 (success) { + if (ret == IPHONE_E_SUCCESS) { log_debug_msg("lockdownd_pair_device: pair success\n"); store_device_public_key(uid, public_key_b64); ret = IPHONE_E_SUCCESS; @@ -914,81 +900,85 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char if (!client->in_SSL && !lockdownd_start_SSL_session(client, host_id)) return IPHONE_E_SSL_ERROR; - char *XML_query, **dictionary; + + plist_t plist = NULL; + dict_t dict = NULL; + char *XML_content = NULL; uint32_t length, i = 0, port_loc = 0, bytes = 0; - uint8_t result = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; free(host_id); host_id = NULL; - xmlDocPtr plist = new_plist(); - xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - xmlNode *key; - key = add_key_str_dict_element(plist, dict, "Request", "StartService", 1); - if (!key) { - xmlFreeDoc(plist); - return IPHONE_E_UNKNOWN_ERROR; - } - key = add_key_str_dict_element(plist, dict, "Service", service, 1); - if (!key) { - xmlFreeDoc(plist); - return IPHONE_E_UNKNOWN_ERROR; - } + plist_new_plist(&plist); + plist_new_dict_in_plist(plist, &dict); + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartService"); + plist_add_dict_element(dict, "Service", PLIST_STRING, (void *) service); + plist_to_xml(plist, &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); - xmlDocDumpMemory(plist, (xmlChar **) & XML_query, &length); + xmlFree(XML_content); + XML_content = NULL; + plist_free(plist); + plist = NULL; - ret = iphone_lckd_send(client, XML_query, length, &bytes); - free(XML_query); if (IPHONE_E_SUCCESS != ret) return ret; - ret = iphone_lckd_recv(client, &XML_query, &bytes); - xmlFreeDoc(plist); + ret = iphone_lckd_recv(client, &XML_content, &bytes); + if (IPHONE_E_SUCCESS != ret) return ret; + xml_to_plist(XML_content, bytes, &plist); + if (!plist) + return IPHONE_E_PLIST_ERROR; + + if (bytes <= 0) return IPHONE_E_NOT_ENOUGH_DATA; else { - plist = xmlReadMemory(XML_query, bytes, NULL, NULL, 0); - if (!plist) - return IPHONE_E_UNKNOWN_ERROR; - dict = xmlDocGetRootElement(plist); - if (!dict) - return IPHONE_E_UNKNOWN_ERROR; - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) - break; - } - if (!dict) - return IPHONE_E_UNKNOWN_ERROR; - dictionary = read_dict_element_strings(dict); - - for (i = 0; dictionary[i]; i += 2) { - log_debug_msg("lockdownd_start_service() dictionary %s: %s\n", dictionary[i], dictionary[i + 1]); - - if (!xmlStrcmp(dictionary[i], "Port")) { - port_loc = atoi(dictionary[i + 1]); - log_debug_msg("lockdownd_start_service() atoi'd port: %i\n", port); - } - - if (!xmlStrcmp(dictionary[i], "Result")) { - if (!xmlStrcmp(dictionary[i + 1], "Success")) { - result = 1; - } - } + plist_t query_node = find_query_node(plist, "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(plist, 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 port_value = 0; + + get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key)); + get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key)); + get_type_and_value(port_value_node, &port_value_type, (void *) (&port_value)); + + if (result_key_type == PLIST_KEY && + result_value_type == PLIST_STRING && + port_key_type == PLIST_KEY && + port_value_type == PLIST_UINT64 && + !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_query); + log_debug_msg(XML_content); log_debug_msg("end data received by lockdownd_start_service()\n"); - free(XML_query); - xmlFreeDoc(plist); - free_dictionary(dictionary); - if (port && result) { + free(XML_content); + plist_free(plist); + if (port && ret == IPHONE_E_SUCCESS) { *port = port_loc; return IPHONE_E_SUCCESS; } else diff --git a/src/plist.c b/src/plist.c index 5b61570..1c00cc6 100644 --- a/src/plist.c +++ b/src/plist.c @@ -946,6 +946,73 @@ GNode *find_query_node(plist_t plist, char *key, char *request) return NULL; } +char compare_node_value(plist_type type, struct plist_data *data, void *value) +{ + char res = FALSE; + switch (type) { + case PLIST_BOOLEAN: + res = data->boolval == *((char *) value) ? TRUE : FALSE; + break; + case PLIST_UINT8: + res = data->intval8 == *((uint8_t *) value) ? TRUE : FALSE; + break; + case PLIST_UINT16: + res = data->intval16 == *((uint16_t *) value) ? TRUE : FALSE; + break; + case PLIST_UINT32: + res = data->intval32 == *((uint32_t *) value) ? TRUE : FALSE; + break; + case PLIST_UINT64: + res = data->intval64 == *((uint64_t *) value) ? TRUE : FALSE; + break; + case PLIST_FLOAT32: + res = data->realval32 == *((float *) value) ? TRUE : FALSE; + break; + case PLIST_FLOAT64: + res = data->realval64 == *((double *) value) ? TRUE : FALSE; + break; + case PLIST_KEY: + case PLIST_STRING: + res = !strcmp(data->strval, ((char *) value)); + break; + case PLIST_UNICODE: + res = !wcscmp(data->unicodeval, ((wchar_t *) value)); + break; + case PLIST_DATA: + res = !strcmp(data->buff, ((char *) value)); + break; + case PLIST_ARRAY: + case PLIST_DICT: + case PLIST_DATE: + case PLIST_PLIST: + default: + break; + } + return res; +} + +GNode *find_node(plist_t plist, plist_type type, void *value) +{ + if (!plist) + return NULL; + + GNode *current = NULL; + for (current = plist->children; current; current = current->next) { + + struct plist_data *data = (struct plist_data *) current->data; + + if (data->type == type && compare_node_value(type, data, value)) { + return current; + } + if (data->type == PLIST_DICT || data->type == PLIST_ARRAY || data->type == PLIST_PLIST) { + GNode *sub = find_node(current, type, value); + if (sub) + return sub; + } + } + return NULL; +} + void get_type_and_value(GNode * node, plist_type * type, void *value) { if (!node) diff --git a/src/plist.h b/src/plist.h index ffc00e4..34e3934 100644 --- a/src/plist.h +++ b/src/plist.h @@ -84,5 +84,6 @@ void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist); void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); GNode *find_query_node(plist_t plist, char *key, char *request); +GNode *find_node(plist_t plist, plist_type type, void *value); void get_type_and_value(GNode * node, plist_type * type, void *value); #endif -- cgit v1.1-32-gdbae From 36eff97cba9049ce7ec194cb4f8926c7876368eb Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 1 Dec 2008 21:12:02 +0100 Subject: finish new plist API migration. --- src/lockdown.c | 183 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 90 insertions(+), 93 deletions(-) diff --git a/src/lockdown.c b/src/lockdown.c index 3d39fbd..55e2e65 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -662,113 +662,110 @@ iphone_error_t lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_ */ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const char *HostID) { - xmlDocPtr plist = new_plist(); - xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - xmlNode *key; - char *what2send = NULL, **dictionary = NULL; - uint32_t len = 0, bytes = 0, return_me = 0, i = 0; + plist_t plist = NULL; + dict_t dict = NULL; + char *XML_content = NULL; + uint32_t length = 0, bytes = 0, return_me = 0; + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - // end variables - key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); - if (!key) { - log_debug_msg("Couldn't add a key.\n"); - xmlFreeDoc(plist); - return IPHONE_E_DICT_ERROR; - } - key = add_key_str_dict_element(plist, dict, "Request", "StartSession", 1); - if (!key) { - log_debug_msg("Couldn't add a key.\n"); - xmlFreeDoc(plist); - return IPHONE_E_DICT_ERROR; - } + /* Setup DevicePublicKey request plist */ + plist_new_plist(&plist); + plist_new_dict_in_plist(plist, &dict); + plist_add_dict_element(dict, "HostID", PLIST_STRING, (void *) HostID); + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartSession"); + plist_to_xml(plist, &XML_content, &length); + log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - xmlDocDumpMemory(plist, (xmlChar **) & what2send, &len); - ret = iphone_lckd_send(control, what2send, len, &bytes); + ret = iphone_lckd_send(control, XML_content, length, &bytes); - xmlFree(what2send); - xmlFreeDoc(plist); + xmlFree(XML_content); + XML_content = NULL; + plist_free(plist); + plist = NULL; if (ret != IPHONE_E_SUCCESS) return ret; if (bytes > 0) { - ret = iphone_lckd_recv(control, &what2send, &len); - plist = xmlReadMemory(what2send, len, NULL, NULL, 0); - dict = xmlDocGetRootElement(plist); - if (!dict) - return IPHONE_E_DICT_ERROR; - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) - break; - } - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(what2send); - for (i = 0; dictionary[i]; i += 2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "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"); - - free_dictionary(dictionary); - - 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; - } + 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, &plist); + if (!plist) + return IPHONE_E_PLIST_ERROR; + + plist_t query_node = find_query_node(plist, "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; + + get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key)); + get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + + xmlFree(XML_content); + XML_content = NULL; + plist_free(plist); + plist = 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"); - for (i = 0; dictionary[i]; i += 2) { - log_debug_msg("\t%s: %s\n", dictionary[i], dictionary[i + 1]); - } - - - free_dictionary(dictionary); return IPHONE_E_SSL_ERROR; } else { log_debug_msg("Didn't get enough bytes.\n"); -- cgit v1.1-32-gdbae From 7563917755cf58cee80fbd5bc56a1ab0f563963a Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 1 Dec 2008 21:23:58 +0100 Subject: cleanup unused functions. --- dev/plutil.c | 1 + src/plist.c | 153 ++++------------------------------------------------------- src/plist.h | 12 ----- 3 files changed, 9 insertions(+), 157 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index 0e25291..4a34077 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -10,6 +10,7 @@ #include #include + int main(int argc, char *argv[]) { struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); diff --git a/src/plist.c b/src/plist.c index 1c00cc6..5d8fc0e 100644 --- a/src/plist.c +++ b/src/plist.c @@ -101,151 +101,6 @@ void free_plist(xmlDocPtr plist) xmlFreeDoc(plist); } -/** Adds a new node as a child to a given node. - * - * This is a lower level function so you probably want to use - * add_key_str_dict_element, add_key_dict_node or add_key_data_dict_element - * instead. - * - * @param plist The plist XML document to which the to_node belongs. - * @param name The name of the new node. - * @param content The string containing the text node of the new node. - * @param to_node The node to attach the child node to. If none is given, the - * root node of the given document is used. - * @param depth The number of tabs to indent the new node. - * - * @return The newly created node. - */ -xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode * to_node, int depth) -{ - int i = 0; - xmlNode *child; - - if (!plist) - return NULL; - assert(depth >= 0); - if (!to_node) - to_node = xmlDocGetRootElement(plist); - - for (i = 0; i < depth; i++) { - xmlNodeAddContent(to_node, "\t"); - } - child = xmlNewChild(to_node, NULL, name, content); - xmlNodeAddContent(to_node, "\n"); - - return child; -} - -/** Adds a string key-pair to a plist XML document. - * - * @param plist The plist XML document to add the new node to. - * @param dict The dictionary node within the plist XML document to add the new node to. - * @param key The string containing the key value. - * @param value The string containing the value. - * @param depth The number of tabs to indent the new node. - * - * @return The newly created key node. - */ -xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth) -{ - xmlNode *keyPtr; - - keyPtr = add_child_to_plist(plist, "key", key, dict, depth); - add_child_to_plist(plist, "string", value, dict, depth); - - return keyPtr; -} - -/** Adds a new dictionary key-pair to a plist XML document. - * - * @param plist The plist XML document to add the new node to. - * @param dict The dictionary node within the plist XML document to add the new node to. - * @param key The string containing the key value. - * @param value The string containing the value. - * @param depth The number of tabs to indent the new node. - * - * @return The newly created dict node. - */ -xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth) -{ - xmlNode *child; - - add_child_to_plist(plist, "key", key, dict, depth); - child = add_child_to_plist(plist, "dict", value, dict, depth); - - return child; -} - -/** Adds a new data dictionary key-pair to a plist XML document. - * - * @param plist The plist XML document to add the new node to. - * @param dict The dictionary node within the plist XML document to add the new node to. - * @param key The string containing the key value. - * @param value The string containing the value. - * @param depth The number of tabs to indent the new node. - * - * @return The newly created key node. - */ -xmlNode *add_key_data_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth) -{ - xmlNode *keyPtr; - - keyPtr = add_child_to_plist(plist, "key", key, dict, depth); - add_child_to_plist(plist, "data", format_string(value, 60, depth), dict, depth); - - return keyPtr; -} - -/** Reads a set of keys and strings into an array from a plist XML document. - * - * @param dict The root XMLNode of a plist XML document to be read. - * - * @return An array where each even number is a key and the odd numbers are - * values. If the odd number is \0, that's the end of the list. - */ -char **read_dict_element_strings(xmlNode * dict) -{ - char **return_me = NULL, **old = NULL; - int current_length = 0; - int current_pos = 0; - xmlNode *dict_walker; - - for (dict_walker = dict->children; dict_walker; dict_walker = dict_walker->next) { - if (!xmlStrcmp(dict_walker->name, "key")) { - current_length += 2; - old = return_me; - return_me = realloc(return_me, sizeof(char *) * current_length); - if (!return_me) { - free(old); - return NULL; - } - return_me[current_pos++] = xmlNodeGetContent(dict_walker); - return_me[current_pos++] = xmlNodeGetContent(dict_walker->next->next); - } - } - - old = return_me; - return_me = realloc(return_me, sizeof(char *) * (current_length + 1)); - return_me[current_pos] = NULL; - - return return_me; -} - -/** Destroys a dictionary as returned by read_dict_element_strings - */ -void free_dictionary(char **dictionary) -{ - int i = 0; - - if (!dictionary) - return; - - for (i = 0; dictionary[i]; i++) { - free(dictionary[i]); - } - - free(dictionary); -} /* * Binary propertylist code follows @@ -357,6 +212,14 @@ void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void * { } +/** Adds a new key pair to a dict. + * + * @param dict The dict node in the plist. + * @param key the key name of the key pair. + * @param type The the type of the value in the key pair. + * @param value a pointer to the actual buffer containing the value. WARNING : the buffer is supposed to match the type of the value + * + */ void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value) { if (!dict || !key || !value) diff --git a/src/plist.h b/src/plist.h index 34e3934..ed3d2b2 100644 --- a/src/plist.h +++ b/src/plist.h @@ -22,8 +22,6 @@ #ifndef PLIST_H #define PLIST_H -#include -#include #include #include @@ -33,16 +31,7 @@ #include char *format_string(const char *buf, int cols, int depth); -xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); -xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); -xmlNode *add_key_data_dict_element(xmlDocPtr plist, xmlNode * dict, const char *key, const char *value, int depth); -xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode * to_node, int depth); -void free_plist(xmlDocPtr plist); -xmlDocPtr new_plist(); - -char **read_dict_element_strings(xmlNode * dict); -void free_dictionary(char **dictionary); /* Binary plist stuff */ @@ -70,7 +59,6 @@ typedef GNode *plist_t; typedef GNode *dict_t; typedef GNode *array_t; - void plist_new_plist(plist_t * plist); void plist_new_dict_in_plist(plist_t plist, dict_t * dict); void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array); -- cgit v1.1-32-gdbae From 1a06347d27ca51283de3a9ff21e138a3ea9ba9b6 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 8 Dec 2008 22:47:02 +0100 Subject: cleanup binary parsing and move stuff around. --- src/lockdown.c | 2 +- src/plist.c | 854 +++++++++++++++++++++++++++++++-------------------------- src/plist.h | 18 +- 3 files changed, 489 insertions(+), 385 deletions(-) diff --git a/src/lockdown.c b/src/lockdown.c index 55e2e65..ae077b7 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -963,7 +963,7 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char if (result_key_type == PLIST_KEY && result_value_type == PLIST_STRING && port_key_type == PLIST_KEY && - port_value_type == PLIST_UINT64 && + 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; diff --git a/src/plist.c b/src/plist.c index 5d8fc0e..c691c16 100644 --- a/src/plist.c +++ b/src/plist.c @@ -19,19 +19,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include + #include #include #include "utils.h" #include "plist.h" #include +/********************************************** +* * +* Abstract Plist stuff * +* * +**********************************************/ + + + + + -const char *plist_base = "\n\ -\n\ -\n\ -\0"; /** Formats a block of text to be a given indentation and width. * @@ -72,34 +77,7 @@ char *format_string(const char *buf, int cols, int depth) return new_buf; } -/** Creates a new plist XML document. - * - * @return The plist XML document. - */ -xmlDocPtr new_plist() -{ - char *plist = strdup(plist_base); - xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); - - if (!plist_xml) - return NULL; - - free(plist); - - return plist_xml; -} - -/** Destroys a previously created XML document. - * - * @param plist The XML document to destroy. - */ -void free_plist(xmlDocPtr plist) -{ - if (!plist) - return; - xmlFreeDoc(plist); -} /* @@ -117,29 +95,7 @@ void free_plist(xmlDocPtr plist) * - parse_nodes() will return the first node it encounters, which is usually the "root" node. */ -uint32_t uipow(uint32_t value, uint32_t power) -{ - if (!power) - return 1; - int i = 0, oVal = value; - for (i = 1; i < power; i++) { - value *= oVal; - } - return value; -} -void byte_convert(char *address, size_t size) -{ - int i = 0, j = 0; - char tmp = '\0'; - - for (i = 0; i < (size / 2); i++) { - tmp = address[i]; - j = ((size - 1) + 0) - i; - address[i] = address[j]; - address[j] = tmp; - } -} void print_bytes(char *val, size_t size) { @@ -154,39 +110,17 @@ void print_bytes(char *val, size_t size) struct plist_data { union { char boolval; - uint8_t intval8; - uint16_t intval16; - uint32_t intval32; - uint64_t intval64; - float realval32; - double realval64; + uint64_t intval; + double realval; char *strval; wchar_t *unicodeval; - struct { - char *buff; - uint8_t ref_size; - }; + char *buff; }; uint64_t length; plist_type type; }; -enum { - BPLIST_TRUE = 0x08, - BPLIST_FALSE = 0x09, - BPLIST_FILL = 0x0F, /* will be used for length grabbing */ - BPLIST_INT = 0x10, - BPLIST_REAL = 0x20, - BPLIST_DATE = 0x33, - BPLIST_DATA = 0x40, - BPLIST_STRING = 0x50, - BPLIST_UNICODE = 0x60, - BPLIST_UID = 0x70, - BPLIST_ARRAY = 0xA0, - BPLIST_SET = 0xC0, - BPLIST_DICT = 0xD0, - BPLIST_MASK = 0xF0 -}; + void plist_new_plist(plist_t * plist) { @@ -239,23 +173,11 @@ void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value case PLIST_BOOLEAN: val->boolval = *((char *) value); break; - case PLIST_UINT8: - val->intval8 = *((uint8_t *) value); - break; - case PLIST_UINT16: - val->intval16 = *((uint16_t *) value); - break; - case PLIST_UINT32: - val->intval32 = *((uint32_t *) value); - break; - case PLIST_UINT64: - val->intval64 = *((uint64_t *) value); + case PLIST_UINT: + val->intval = *((uint64_t *) value); break; - case PLIST_FLOAT32: - val->realval32 = *((float *) value); - break; - case PLIST_FLOAT64: - val->realval64 = *((double *) value); + case PLIST_REAL: + val->realval = *((double *) value); break; case PLIST_STRING: val->strval = strdup((char *) value); @@ -282,11 +204,55 @@ void plist_free(plist_t plist) g_node_destroy(plist); } +/********************************************** +* * +* Xml Plist stuff * +* * +**********************************************/ + +#include +#include + + +const char *plist_base = "\n\ +\n\ +\n\ +\0"; + struct xml_node { xmlNodePtr xml; uint32_t depth; }; +/** Creates a new plist XML document. + * + * @return The plist XML document. + */ +xmlDocPtr new_plist() +{ + char *plist = strdup(plist_base); + xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); + + if (!plist_xml) + return NULL; + + free(plist); + + return plist_xml; +} + +/** Destroys a previously created XML document. + * + * @param plist The XML document to destroy. + */ +void free_plist(xmlDocPtr plist) +{ + if (!plist) + return; + + xmlFreeDoc(plist); +} + void node_to_xml(GNode * node, gpointer xml_struct) { if (!node) @@ -311,34 +277,14 @@ void node_to_xml(GNode * node, gpointer xml_struct) } break; - case PLIST_UINT8: - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval8); - break; - - case PLIST_UINT16: - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval16); - break; - - case PLIST_UINT32: - tag = "integer"; - val = g_strdup_printf("%u", node_data->intval32); - break; - - case PLIST_UINT64: + case PLIST_UINT: tag = "integer"; - val = g_strdup_printf("%lu", (long unsigned int) node_data->intval64); - break; - - case PLIST_FLOAT32: - tag = "real"; - val = g_strdup_printf("%f", node_data->realval32); + val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); break; - case PLIST_FLOAT64: + case PLIST_REAL: tag = "real"; - val = g_strdup_printf("%Lf", (long double) node_data->intval64); + val = g_strdup_printf("%Lf", (long double) node_data->realval); break; case PLIST_STRING: @@ -358,7 +304,7 @@ void node_to_xml(GNode * node, gpointer xml_struct) case PLIST_DATA: tag = "data"; - val = format_string(node_data->buff, 60, 0); + val = format_string(node_data->buff, 60, xstruct->depth); break; case PLIST_ARRAY: tag = "array"; @@ -435,15 +381,15 @@ void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) if (!xmlStrcmp(node->name, "integer")) { char *strval = xmlNodeGetContent(node); - data->intval64 = atoi(strval); - data->type = PLIST_UINT64; + data->intval = atoi(strval); + data->type = PLIST_UINT; continue; } if (!xmlStrcmp(node->name, "real")) { char *strval = xmlNodeGetContent(node); - data->realval64 = atof(strval); - data->type = PLIST_FLOAT64; + data->realval = atof(strval); + data->type = PLIST_REAL; continue; } @@ -493,294 +439,460 @@ void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); } -GNode *parse_raw_node(const char *bpbuffer, uint32_t bplength, uint32_t * position, uint8_t ref_size) +void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) { - if (!position || !bpbuffer || !bplength) - return NULL; + xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - uint8_t modifier = 0; struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - GNode *new_node = g_node_new(data); - GNode *length_stupidity = NULL; + *plist = g_node_new(data); + data->type = PLIST_PLIST; + xml_to_node(root_node, *plist); +} - int myPos = *position; - if (myPos == bplength || (myPos + 1) == bplength) { - g_node_destroy(new_node); - return NULL; - } // end of string - uint32_t length = 0; - if (!myPos) { - if (strncmp(bpbuffer, "bplist00", strlen("bplist00"))) { - return NULL; // badness! - } - myPos += strlen("bplist00"); - } - // Get the node's type. - if (bpbuffer[myPos] == BPLIST_DATE) { // handle date separately, but do it as a real - // better handling of date; basically interpret as real or double - data->type = BPLIST_DATE; - length = 8; // always 8 for "date" (Apple intended it, not me) - myPos++; - memcpy(&data->realval64, bpbuffer + myPos, sizeof(data->realval64)); - byte_convert((char *) &data->realval64, sizeof(data->realval64)); - myPos += length; - *position = myPos; - return new_node; - } - int type = bpbuffer[myPos] & BPLIST_MASK; - data->length = bpbuffer[myPos] & BPLIST_FILL; +/********************************************** +* * +* Binary Plist stuff * +* * +**********************************************/ - if (!type) { - // what? check if it's a boolean. - if (bpbuffer[myPos] == BPLIST_TRUE || bpbuffer[myPos] == BPLIST_FALSE) { - // okay, so it is. Carry on. - data->type = PLIST_BOOLEAN; - data->boolval = TRUE; - data->length = 0; - } else { - // er, what? we have a bad type here. Return NULL. - g_node_destroy(new_node); - //printf("parse_raw_node: lol type: type given %x\n", bpbuffer[myPos]); - return NULL; - } - } +/* Magic marker and size. */ +#define BPLIST_MAGIC "bplist" +#define BPLIST_MAGIC_SIZE 6 - myPos++; // puts us in the data. - if (length == BPLIST_FILL) { // Data happens to contain length... - // what? you're going to make me parse an int for the length. You suck. - *position = myPos; - length_stupidity = parse_raw_node(bpbuffer, bplength, &myPos, ref_size); - switch (((struct plist_data *) length_stupidity->data)->type) { - case PLIST_UINT8: - data->length = ((struct plist_data *) length_stupidity->data)->intval8; - break; - case PLIST_UINT16: - data->length = ((struct plist_data *) length_stupidity->data)->intval16; - break; - case PLIST_UINT32: - data->length = ((struct plist_data *) length_stupidity->data)->intval32; - break; - case PLIST_UINT64: - data->length = ((struct plist_data *) length_stupidity->data)->intval64; - break; - default: - g_node_destroy(new_node); - g_node_destroy(length_stupidity); - return NULL; - } - // There, we have our fucking length now. - *position = myPos; - g_node_destroy(length_stupidity); // cleanup +#define BPLIST_VERSION "00" +#define BPLIST_VERSION_SIZE 2 + + +#define BPLIST_TRL_SIZE 26 +#define BPLIST_TRL_OFFSIZE_IDX 0 +#define BPLIST_TRL_PARMSIZE_IDX 1 +#define BPLIST_TRL_NUMOBJ_IDX 2 +#define BPLIST_TRL_ROOTOBJ_IDX 10 +#define BPLIST_TRL_OFFTAB_IDX 18 + +enum { + BPLIST_NULL = 0x00, + BPLIST_TRUE = 0x08, + BPLIST_FALSE = 0x09, + BPLIST_FILL = 0x0F, /* will be used for length grabbing */ + BPLIST_UINT = 0x10, + BPLIST_REAL = 0x20, + BPLIST_DATE = 0x30, + BPLIST_DATA = 0x40, + BPLIST_STRING = 0x50, + BPLIST_UNICODE = 0x60, + BPLIST_UID = 0x70, + BPLIST_ARRAY = 0xA0, + BPLIST_SET = 0xC0, + BPLIST_DICT = 0xD0, + BPLIST_MASK = 0xF0 +}; + +void byte_convert(char *address, size_t size) +{ + int i = 0, j = 0; + char tmp = '\0'; + + for (i = 0; i < (size / 2); i++) { + tmp = address[i]; + j = ((size - 1) + 0) - i; + address[i] = address[j]; + address[j] = tmp; } - // Now we're in the data. - // Error-checking sorta - if ((myPos + data->length) >= bplength) { - data->length = bplength - myPos; // truncate the object +} + +#include +#define swap_n_bytes(x, n) \ + n == 8 ? bswap_64(*(uint64_t *)(x)) : \ + (n == 4 ? bswap_32(*(uint32_t *)(x)) : \ + (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) )) + +#define be64dec(x) bswap_64( *(uint64_t*)(x) ) + +GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + size = 1 << size; // make length less misleading + switch (size) { + case sizeof(uint8_t): + data->intval = bnode[0]; + break; + case sizeof(uint16_t): + memcpy(&data->intval, bnode, size); + data->intval = ntohs(data->intval); + break; + case sizeof(uint32_t): + memcpy(&data->intval, bnode, size); + data->intval = ntohl(data->intval); + break; + case sizeof(uint64_t): + memcpy(&data->intval, bnode, size); + byte_convert((char *) &data->intval, size); + break; + default: + free(data); + return NULL; + }; + + *next_object = bnode + size; + data->type = PLIST_UINT; + return g_node_new(data); +} + +GNode *parse_real_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + size = 1 << size; // make length less misleading + switch (size) { + case sizeof(float): + memcpy(&data->realval, bnode, size); + byte_convert((char *) &data->realval, size); + break; + case sizeof(double): + memcpy(&data->realval, bnode, size); + byte_convert((char *) &data->realval, size); + break; + default: + free(data); + return NULL; } - // And now for the greatest show on earth: the giant fucking switch statement. + data->type = PLIST_REAL; + return g_node_new(data); +} + +GNode *parse_string_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_STRING; + data->strval = (char *) malloc(sizeof(char) * (size + 1)); + memcpy(data->strval, bnode, size); + data->strval[size] = '\0'; + + return g_node_new(data); +} + +GNode *parse_unicode_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_UNICODE; + data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1)); + memcpy(data->unicodeval, bnode, size); + data->unicodeval[size] = '\0'; + + return g_node_new(data); +} + +GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_DATA; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size); + memcpy(data->buff, bnode, sizeof(char) * size); + + return g_node_new(data); +} + +GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_DICT; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2); + memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2); + + return g_node_new(data); +} + +GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_ARRAY; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size * ref_size); + memcpy(data->buff, bnode, sizeof(char) * size * ref_size); + + return g_node_new(data); +} + +plist_type plist_get_node_type(plist_t node) +{ + return ((struct plist_data *) node->data)->type; +} + +uint64_t plist_get_node_uint_val(plist_t node) +{ + if (PLIST_UINT == plist_get_node_type(node)) + return ((struct plist_data *) node->data)->intval; + else + return 0; +} + + +GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) +{ + if (!object) + return NULL; + + uint16_t type = *object & 0xF0; + uint64_t size = *object & 0x0F; + object++; + switch (type) { - case BPLIST_INT: - data->length = uipow(2, data->length); // make length less misleading - switch (data->length) { - case sizeof(uint8_t): - data->type = PLIST_UINT8; - data->intval8 = bpbuffer[myPos]; - break; - case sizeof(uint16_t): - data->type = PLIST_UINT16; - memcpy(&data->intval16, bpbuffer + myPos, sizeof(uint16_t)); - data->intval16 = ntohs(data->intval16); - break; - case sizeof(uint32_t): - data->type = PLIST_UINT32; - memcpy(&data->intval32, bpbuffer + myPos, sizeof(uint32_t)); - data->intval32 = ntohl(data->intval32); - break; - case sizeof(uint64_t): - data->type = PLIST_UINT64; - memcpy(&data->intval64, bpbuffer + myPos, sizeof(uint64_t)); - byte_convert((char *) &data->intval64, sizeof(uint64_t)); - break; + + case BPLIST_NULL: + switch (size) { + + case BPLIST_TRUE: + { + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + data->type = PLIST_BOOLEAN; + data->boolval = TRUE; + return g_node_new(data); + } + + case BPLIST_FALSE: + { + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + data->type = PLIST_BOOLEAN; + data->boolval = FALSE; + return g_node_new(data); + } + + case BPLIST_NULL: default: - g_node_destroy(new_node); - printf("parse_raw_node: lol: invalid int: size given %lu\n", (long unsigned int) length); - printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); return NULL; } - break; + + case BPLIST_UINT: + return parse_uint_node(object, size, next_object); case BPLIST_REAL: - data->length = uipow(2, data->length); - switch (data->length) { - case sizeof(float): - data->type = PLIST_FLOAT32; - memcpy(&data->realval32, bpbuffer + myPos, data->length); - byte_convert((char *) &data->realval32, sizeof(float)); //necessary ?? - break; - case sizeof(double): - data->type = PLIST_FLOAT64; - memcpy(&data->realval64, bpbuffer + myPos, data->length); - byte_convert((char *) &data->realval64, sizeof(double)); - break; - default: - g_node_destroy(new_node); - printf("parse_raw_node: lol: invalid real: size given %lu\n", (long unsigned int) length); - printf("parse_raw_node: lol: by the way sizeof(uint64) = %i\n", sizeof(uint64_t)); + return parse_real_node(object, size); + + case BPLIST_DATE: + if (3 != size) return NULL; + else + return parse_real_node(object, size); + + case BPLIST_DATA: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); } - break; + return parse_data_node(object, size, dict_size); case BPLIST_STRING: - data->type = PLIST_STRING; - data->strval = (char *) malloc(sizeof(char) * data->length); - memcpy(data->strval, bpbuffer + myPos, data->length); - break; + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_string_node(object, size); case BPLIST_UNICODE: - data->type = PLIST_UNICODE; - data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * data->length); - memcpy(data->unicodeval, bpbuffer + myPos, data->length); - break; + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_unicode_node(object, size); + + case BPLIST_UID: + case BPLIST_ARRAY: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_array_node(object, size, dict_size); + + case BPLIST_SET: + case BPLIST_DICT: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + object++; + size = plist_get_node_uint_val(size_node); + } + return parse_dict_node(object, size, dict_size); - case BPLIST_DICT: /* returning a raw dict, it forward-references, so. */ - data->length = data->length * 2; // dicts lie - data->type = PLIST_DICT; + } + return NULL; +} - case BPLIST_ARRAY: /* returning a raw array, it forward-references, so. */ - data->ref_size = ref_size; // in arrays and dicts, the "ref size" alluded to in the trailer applies, and should be stored in intval8 so as to save space. - if (data->type == 0) - data->type = PLIST_ARRAY; - case BPLIST_DATA: - if (data->type == 0) - data->type = PLIST_DATA; - default: /* made to hold raw data. */ - modifier = (data->ref_size > 0) ? data->ref_size : 1; - data->buff = (char *) malloc(sizeof(char) * (data->length * modifier)); - memcpy(data->buff, bpbuffer + myPos, (data->length * modifier)); +void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) +{ + uint64_t num_objects = g_node_n_nodes(plist, G_TRAVERSE_ALL); +} + + + +gpointer copy_plist_data(gconstpointer src, gpointer data) +{ + struct plist_data *srcdata = (struct plist_data *) src; + struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + dstdata->type = srcdata->type; + dstdata->length = srcdata->length; + switch (dstdata->type) { + case PLIST_BOOLEAN: + dstdata->boolval = srcdata->boolval; + break; + case PLIST_UINT: + dstdata->intval = srcdata->intval; + break; + case PLIST_DATE: + case PLIST_REAL: + dstdata->realval = srcdata->realval; + break; + case PLIST_KEY: + case PLIST_STRING: + dstdata->strval = strdup(srcdata->strval); + break; + case PLIST_UNICODE: + dstdata->unicodeval = wcsdup(srcdata->unicodeval); + break; + case PLIST_PLIST: + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length); + memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length); break; + default: + break; } - myPos += data->length; - *position = myPos; - return new_node; + return dstdata; } -plist_t parse_nodes(const char *bpbuffer, uint32_t bplength, uint32_t * position) +void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) { - plist_t *nodeslist = NULL, *newaddr = NULL; - plist_t new_node = NULL, root_node = NULL; + //first check we have enough data + if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) + return; + //check that plist_bin in actually a plist + if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) + return; + //check for known version + if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) + return; - uint32_t nodeslength = 0; - uint8_t offset_size = 0, dict_param_size = 0; - offset_size = bpbuffer[bplength - 26]; - dict_param_size = bpbuffer[bplength - 25]; - uint64_t current_offset = 0; - uint64_t num_objects = 0, root_object = 0, offset_table_index = 0; - memcpy(&num_objects, bpbuffer + bplength - 24, sizeof(uint64_t)); - memcpy(&root_object, bpbuffer + bplength - 16, sizeof(uint64_t)); - memcpy(&offset_table_index, bpbuffer + bplength - 8, sizeof(uint64_t)); - byte_convert((char *) &num_objects, sizeof(uint64_t)); - byte_convert((char *) &root_object, sizeof(uint64_t)); - byte_convert((char *) &offset_table_index, sizeof(uint64_t)); - - log_debug_msg("Offset size: %i\nGiven: %i\n", offset_size, bpbuffer[bplength - 26]); - log_debug_msg("Ref size: %i\nGiven: %i\n", dict_param_size, bpbuffer[bplength - 25]); - log_debug_msg("Number of objects: %lli\nGiven: %llu\n", num_objects, *(bpbuffer + bplength - 24)); - log_debug_msg("Root object index: %lli\nGiven: %llu\n", root_object, *(bpbuffer + bplength - 16)); - log_debug_msg("Offset table index: %lli\nGiven: %llu\n", offset_table_index, *(bpbuffer + bplength - 8)); - log_debug_msg("Size of uint64: %i\n", sizeof(uint64_t)); - - int i = 0, j = 0, k = 0, str_i = 0, str_j = 0; - uint32_t index1 = 0, index2 = 0; + //now parse trailer + const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); + + uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; + uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; + uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); + uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); + uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); + log_debug_msg("Offset size: %i\n", offset_size); + log_debug_msg("Ref size: %i\n", dict_param_size); + log_debug_msg("Number of objects: %lli\n", num_objects); + log_debug_msg("Root object index: %lli\n", root_object); + log_debug_msg("Offset table index: %lli\n", offset_table_index); + + if (num_objects == 0) + return; + + //allocate serialized array of nodes + plist_t *nodeslist = NULL; nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); + if (!nodeslist) - return NULL; + return; + //parse serialized nodes + uint64_t i = 0; + uint64_t current_offset = 0; + const char *offset_table = plist_bin + offset_table_index; for (i = 0; i < num_objects; i++) { - memcpy(¤t_offset, bpbuffer + (offset_table_index + (i * offset_size)), offset_size); - byte_convert((char *) ¤t_offset, - (offset_size <= sizeof(current_offset)) ? offset_size : sizeof(current_offset)); - log_debug_msg("parse_nodes: current_offset = %x\n", current_offset); - nodeslist[i] = parse_raw_node(bpbuffer, bplength, (uint32_t *) & current_offset, dict_param_size); + current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size); + + log_debug_msg("parse_nodes: current_offset = %i\n", current_offset); + char *obj = plist_bin + current_offset; + nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); log_debug_msg("parse_nodes: parse_raw_node done\n"); } + //setup children for structured types + int j = 0, str_i = 0, str_j = 0; + uint32_t index1 = 0, index2 = 0; for (i = 0; i < num_objects; i++) { - // set elements for dicts and arrays and leave the rest alone + log_debug_msg("parse_nodes: on node %i\n", i); struct plist_data *data = (struct plist_data *) nodeslist[i]->data; switch (data->type) { case PLIST_DICT: log_debug_msg("parse_nodes: dictionary found\n"); - for (j = 0; j < (data->length / 2); j++) { - str_i = j * data->ref_size; - str_j = (j + (data->length / 2)) * data->ref_size; - - memcpy(&index1, data->buff + str_i, data->ref_size); - memcpy(&index2, data->buff + str_j, data->ref_size); - - byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index2)); - byte_convert((char *) &index2, (dict_param_size <= sizeof(index2)) ? dict_param_size : sizeof(index2)); - - g_node_append(nodeslist[i], nodeslist[index1]); - g_node_append(nodeslist[i], nodeslist[index2]); + for (j = 0; j < data->length; j++) { + str_i = j * dict_param_size; + str_j = (j + data->length) * dict_param_size; + + index1 = swap_n_bytes(data->buff + str_i, dict_param_size); + index2 = swap_n_bytes(data->buff + str_j, dict_param_size); + + //first one is actually a key + ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; + //g_node_append(nodeslist[i], nodeslist[index1]); + //g_node_append(nodeslist[i], nodeslist[index2]); + + if (G_NODE_IS_ROOT(nodeslist[index1])) + g_node_append(nodeslist[i], nodeslist[index1]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); + + if (G_NODE_IS_ROOT(nodeslist[index2])) + g_node_append(nodeslist[i], nodeslist[index2]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL)); } - data->length = data->length / 2; free(data->buff); - k = 0; break; case PLIST_ARRAY: log_debug_msg("parse_nodes: array found\n"); for (j = 0; j < data->length; j++) { - log_debug_msg("parse_nodes: array index %i\n", j); - str_j = j * data->ref_size; - memcpy(&index1, data->buff + str_j, data->ref_size); - log_debug_msg("parse_nodes: post-memcpy\n"); - byte_convert((char *) &index1, (dict_param_size <= sizeof(index1)) ? dict_param_size : sizeof(index1)); - log_debug_msg("parse_nodes: post-ntohl\nindex1 = %i\n", index1); - g_node_append(nodeslist[i], nodeslist[index1]); - log_debug_msg("parse_nodes: post-assignment\n"); + str_j = j * dict_param_size; + index1 = swap_n_bytes(data->buff + str_j, dict_param_size); + + //g_node_append(nodeslist[i], nodeslist[index1]); + if (G_NODE_IS_ROOT(nodeslist[index1])) + g_node_append(nodeslist[i], nodeslist[index1]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); } free(data->buff); break; default: - //printf("lol... type %x\n", nodeslist[i]->type); break; - } // those are the only two we need to correct for. + } } - root_node = nodeslist[root_object]; - return root_node; -} - -void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) -{ -} - -void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) -{ - xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); - xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - *plist = g_node_new(data); - data->type = PLIST_PLIST; - xml_to_node(root_node, *plist); - -} - -void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) -{ - uint32_t pos = 0; - *plist = parse_nodes(plist_bin, length, &pos); + *plist = nodeslist[root_object]; } @@ -816,23 +928,11 @@ char compare_node_value(plist_type type, struct plist_data *data, void *value) case PLIST_BOOLEAN: res = data->boolval == *((char *) value) ? TRUE : FALSE; break; - case PLIST_UINT8: - res = data->intval8 == *((uint8_t *) value) ? TRUE : FALSE; - break; - case PLIST_UINT16: - res = data->intval16 == *((uint16_t *) value) ? TRUE : FALSE; - break; - case PLIST_UINT32: - res = data->intval32 == *((uint32_t *) value) ? TRUE : FALSE; - break; - case PLIST_UINT64: - res = data->intval64 == *((uint64_t *) value) ? TRUE : FALSE; + case PLIST_UINT: + res = data->intval == *((uint64_t *) value) ? TRUE : FALSE; break; - case PLIST_FLOAT32: - res = data->realval32 == *((float *) value) ? TRUE : FALSE; - break; - case PLIST_FLOAT64: - res = data->realval64 == *((double *) value) ? TRUE : FALSE; + case PLIST_REAL: + res = data->realval == *((double *) value) ? TRUE : FALSE; break; case PLIST_KEY: case PLIST_STRING: @@ -889,23 +989,11 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) case PLIST_BOOLEAN: *((char *) value) = data->boolval; break; - case PLIST_UINT8: - *((uint8_t *) value) = data->intval8; - break; - case PLIST_UINT16: - *((uint16_t *) value) = data->intval16; - break; - case PLIST_UINT32: - *((uint32_t *) value) = data->intval32; - break; - case PLIST_UINT64: - *((uint64_t *) value) = data->intval64; - break; - case PLIST_FLOAT32: - *((float *) value) = data->realval32; + case PLIST_UINT: + *((uint64_t *) value) = data->intval; break; - case PLIST_FLOAT64: - *((double *) value) = data->realval64; + case PLIST_REAL: + *((double *) value) = data->realval; break; case PLIST_STRING: *((char **) value) = strdup(data->strval); diff --git a/src/plist.h b/src/plist.h index ed3d2b2..df1d3e4 100644 --- a/src/plist.h +++ b/src/plist.h @@ -35,7 +35,7 @@ char *format_string(const char *buf, int cols, int depth); /* Binary plist stuff */ - +/* typedef enum { PLIST_BOOLEAN, PLIST_UINT8, @@ -53,6 +53,22 @@ typedef enum { PLIST_PLIST, PLIST_KEY, } plist_type; +*/ + +typedef enum { + PLIST_BOOLEAN, + PLIST_UINT, + PLIST_REAL, + PLIST_STRING, + PLIST_UNICODE, + PLIST_ARRAY, + PLIST_DICT, + PLIST_DATE, + PLIST_DATA, + PLIST_PLIST, + PLIST_KEY, +} plist_type; + typedef GNode *plist_t; -- cgit v1.1-32-gdbae From 625633203a27f569bea8890cb269132fea83b497 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Wed, 10 Dec 2008 23:22:12 +0100 Subject: add bplist writting capability. --- src/plist.c | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/plist.h | 23 ---- 2 files changed, 356 insertions(+), 50 deletions(-) diff --git a/src/plist.c b/src/plist.c index c691c16..431c64a 100644 --- a/src/plist.c +++ b/src/plist.c @@ -25,6 +25,8 @@ #include "utils.h" #include "plist.h" #include +#include +#include /********************************************** * * @@ -127,7 +129,7 @@ void plist_new_plist(plist_t * plist) if (*plist != NULL) return; struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_PLIST; + data->type = PLIST_DICT; *plist = g_node_new(data); } @@ -191,7 +193,6 @@ void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value case PLIST_ARRAY: case PLIST_DICT: case PLIST_DATE: - case PLIST_PLIST: default: break; } @@ -314,10 +315,6 @@ void node_to_xml(GNode * node, gpointer xml_struct) tag = "dict"; isStruct = TRUE; break; - case PLIST_PLIST: - tag = "plist"; - isStruct = TRUE; - break; case PLIST_DATE: //TODO : handle date tag default: break; @@ -332,8 +329,7 @@ void node_to_xml(GNode * node, gpointer xml_struct) g_free(val); //add return for structured types - if (node_data->type == PLIST_ARRAY || - node_data->type == PLIST_DICT || node_data->type == PLIST_DATA || node_data->type == PLIST_PLIST) + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) xmlNodeAddContent(child_node, "\n"); if (isStruct) { @@ -341,8 +337,7 @@ void node_to_xml(GNode * node, gpointer xml_struct) g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); } //fix indent for structured types - if (node_data->type == PLIST_ARRAY || - node_data->type == PLIST_DICT || node_data->type == PLIST_DATA || node_data->type == PLIST_PLIST) { + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { for (i = 0; i < xstruct->depth; i++) { xmlNodeAddContent(child_node, "\t"); @@ -446,7 +441,7 @@ void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); *plist = g_node_new(data); - data->type = PLIST_PLIST; + data->type = PLIST_DICT; xml_to_node(root_node, *plist); } @@ -512,6 +507,9 @@ void byte_convert(char *address, size_t size) #define be64dec(x) bswap_64( *(uint64_t*)(x) ) +#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8))) +#define get_real_bytes(x) (x >> 32 ? 4 : 8) + GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) { struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); @@ -638,7 +636,6 @@ uint64_t plist_get_node_uint_val(plist_t node) return 0; } - GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) { if (!object) @@ -738,13 +735,6 @@ GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) return NULL; } -void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) -{ - uint64_t num_objects = g_node_n_nodes(plist, G_TRAVERSE_ALL); -} - - - gpointer copy_plist_data(gconstpointer src, gpointer data) { struct plist_data *srcdata = (struct plist_data *) src; @@ -770,7 +760,6 @@ gpointer copy_plist_data(gconstpointer src, gpointer data) case PLIST_UNICODE: dstdata->unicodeval = wcsdup(srcdata->unicodeval); break; - case PLIST_PLIST: case PLIST_DATA: case PLIST_ARRAY: case PLIST_DICT: @@ -856,8 +845,6 @@ void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) //first one is actually a key ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; - //g_node_append(nodeslist[i], nodeslist[index1]); - //g_node_append(nodeslist[i], nodeslist[index2]); if (G_NODE_IS_ROOT(nodeslist[index1])) g_node_append(nodeslist[i], nodeslist[index1]); @@ -895,7 +882,6 @@ void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) *plist = nodeslist[root_object]; } - GNode *find_query_node(plist_t plist, char *key, char *request) { if (!plist) @@ -912,7 +898,7 @@ GNode *find_query_node(plist_t plist, char *key, char *request) if (data->type == PLIST_STRING && !strcmp(data->strval, request)) return current->next; } - if (data->type == PLIST_DICT || data->type == PLIST_ARRAY || data->type == PLIST_PLIST) { + if (data->type == PLIST_DICT || data->type == PLIST_ARRAY) { GNode *sub = find_query_node(current, key, request); if (sub) return sub; @@ -947,7 +933,6 @@ char compare_node_value(plist_type type, struct plist_data *data, void *value) case PLIST_ARRAY: case PLIST_DICT: case PLIST_DATE: - case PLIST_PLIST: default: break; } @@ -967,7 +952,7 @@ GNode *find_node(plist_t plist, plist_type type, void *value) if (data->type == type && compare_node_value(type, data, value)) { return current; } - if (data->type == PLIST_DICT || data->type == PLIST_ARRAY || data->type == PLIST_PLIST) { + if (data->type == PLIST_DICT || data->type == PLIST_ARRAY) { GNode *sub = find_node(current, type, value); if (sub) return sub; @@ -1008,8 +993,352 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) case PLIST_ARRAY: case PLIST_DICT: case PLIST_DATE: - case PLIST_PLIST: default: break; } } + +guint plist_data_hash(gconstpointer key) +{ + struct plist_data *data = (struct plist_data *) ((GNode *) key)->data; + + guint hash = data->type; + guint i = 0; + + char *buff = NULL; + guint size = 0; + + switch (data->type) { + case PLIST_BOOLEAN: + case PLIST_UINT: + case PLIST_REAL: + buff = (char *) &data->intval; + size = 8; + + case PLIST_KEY: + case PLIST_STRING: + buff = data->strval; + size = strlen(buff); + + case PLIST_UNICODE: + buff = data->unicodeval; + size = strlen(buff) * sizeof(wchar_t); + + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + //for these types only hash pointer + buff = &key; + size = sizeof(gconstpointer); + break; + case PLIST_DATE: + default: + break; + } + + //now perform hash + for (i = 0; i < size; buff++, i++) + hash = hash << 7 ^ (*buff); + + return hash; +} + +gboolean plist_data_compare(gconstpointer a, gconstpointer b) +{ + if (!a || !b) + return FALSE; + + if (!((GNode *) a)->data || !((GNode *) b)->data) + return FALSE; + + struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data; + struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data; + + if (val_a->type != val_b->type) + return FALSE; + + switch (val_a->type) { + case PLIST_BOOLEAN: + case PLIST_UINT: + case PLIST_REAL: + if (val_a->intval == val_b->intval) //it is an union so this is sufficient + return TRUE; + else + return FALSE; + + case PLIST_KEY: + case PLIST_STRING: + if (!strcmp(val_a->strval, val_b->strval)) + return TRUE; + else + return FALSE; + case PLIST_UNICODE: + if (!strcmp(val_a->unicodeval, val_b->unicodeval)) + return TRUE; + else + return FALSE; + + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + //compare pointer + if (a == b) + return TRUE; + else + return FALSE; + break; + case PLIST_DATE: + default: + break; + } + return FALSE; +} + +struct serialize_s { + GPtrArray *objects; + GHashTable *ref_table; +}; + +void serialize_plist(GNode * node, gpointer data) +{ + struct serialize_s *ser = (struct serialize_s *) data; + uint64_t current_index = ser->objects->len; + + //first check that node is not yet in objects + gpointer val = g_hash_table_lookup(ser->ref_table, node); + if (val) { + //data is already in table + return; + } + //insert new ref + g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index)); + + //now append current node to object array + g_ptr_array_add(ser->objects, node); + + //now recurse on children + g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data); + return; +} + + + +void write_int(GByteArray * bplist, uint64_t val) +{ + uint64_t size = get_needed_bytes(val); + uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); + buff[0] = BPLIST_UINT | size >> 1; + memcpy(buff + 1, &val, size); + swap_n_bytes(buff + 1, size); + g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); + free(buff); +} + +void write_real(GByteArray * bplist, double val) +{ + uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space + uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); + buff[0] = BPLIST_REAL | size >> 1; + memcpy(buff + 1, &val, size); + swap_n_bytes(buff + 1, size); + g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); + free(buff); +} + +void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) +{ + uint8_t marker = mark | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + uint8_t *buff = (uint8_t *) malloc(size); + memcpy(buff, val, size); + g_byte_array_append(bplist, buff, size); + free(buff); +} + +void write_data(GByteArray * bplist, uint8_t * val, uint64_t size) +{ + write_raw_data(bplist, BPLIST_DATA, val, size); +} + +void write_string(GByteArray * bplist, char *val) +{ + uint64_t size = strlen(val); + write_raw_data(bplist, BPLIST_STRING, val, size); +} + +void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) +{ + uint64_t size = g_node_n_children(node); + uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + + uint64_t idx = 0; + uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); + + GNode *cur = NULL; + int i = 0; + for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { + idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); + memcpy(buff + i * dict_param_size, &idx, dict_param_size); + swap_n_bytes(buff + i * dict_param_size, dict_param_size); + } + + //now append to bplist + g_byte_array_append(bplist, buff, size * dict_param_size); + free(buff); + +} + +void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) +{ + uint64_t size = g_node_n_children(node) / 2; + uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + + uint64_t idx1 = 0; + uint64_t idx2 = 0; + uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); + + GNode *cur = NULL; + int i = 0; + for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { + idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); + memcpy(buff + i * dict_param_size, &idx1, dict_param_size); + swap_n_bytes(buff + i * dict_param_size, dict_param_size); + + idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); + memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); + swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size); + } + + //now append to bplist + g_byte_array_append(bplist, buff, size * dict_param_size); + free(buff); + +} + +void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) +{ + //first serialize tree + + //list of objects + GPtrArray *objects = g_ptr_array_new(); + //hashtable to write only once same nodes + GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); + + //serialize plist + struct serialize_s ser_s = { objects, ref_table }; + g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s); + + //now stream to output buffer + uint8_t offset_size = 0; //unknown yet + uint8_t dict_param_size = get_needed_bytes(objects->len); + uint64_t num_objects = objects->len; + uint64_t root_object = 0; //root is first in list + uint64_t offset_table_index = 0; //unknown yet + + //setup a dynamic bytes array to store bplist in + GByteArray *bplist_buff = g_byte_array_new(); + + //set magic number and version + g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); + g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); + + //write objects and table + int i = 0; + uint8_t *buff = NULL; + uint8_t size = 0; + uint64_t offsets[num_objects]; + for (i = 0; i <= num_objects; i++) { + + offsets[i] = bplist_buff->len; + struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; + + switch (data->type) { + case PLIST_BOOLEAN: + buff = (uint8_t *) malloc(sizeof(uint8_t)); + buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE; + g_byte_array_append(bplist_buff, buff, sizeof(uint8_t)); + free(buff); + break; + + case PLIST_UINT: + write_int(bplist_buff, data->intval); + break; + + case PLIST_REAL: + write_real(bplist_buff, data->realval); + break; + + case PLIST_KEY: + case PLIST_STRING: + write_string(bplist_buff, data->strval); + break; + case PLIST_UNICODE: + //TODO + break; + case PLIST_DATA: + write_data(bplist_buff, data->strval, data->length); + case PLIST_ARRAY: + write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); + break; + case PLIST_DICT: + write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); + break; + case PLIST_DATE: + //TODO + break; + default: + break; + } + } + + //write offsets + offset_size = get_needed_bytes(bplist_buff->len); + for (i = 0; i <= num_objects; i++) { + uint8_t *buff = (uint8_t *) malloc(offset_size); + memcpy(buff, offsets + i, offset_size); + swap_n_bytes(buff, offset_size); + g_byte_array_append(bplist_buff, buff, offset_size); + free(buff); + } + + //setup trailer + num_objects = bswap_64(num_objects); + root_object = bswap_64(root_object); + offset_table_index = bswap_64(offset_table_index); + + char trailer[BPLIST_TRL_SIZE]; + memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); + memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); + memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); + memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t)); + memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t)); + + g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE); + + //duplicate buffer + *plist_bin = (char *) malloc(bplist_buff->len); + memcpy(*plist_bin, bplist_buff->data, bplist_buff->len); + *length = bplist_buff->len; + + g_byte_array_free(bplist_buff, TRUE); +} diff --git a/src/plist.h b/src/plist.h index df1d3e4..63f67f7 100644 --- a/src/plist.h +++ b/src/plist.h @@ -33,28 +33,6 @@ char *format_string(const char *buf, int cols, int depth); -/* Binary plist stuff */ - -/* -typedef enum { - PLIST_BOOLEAN, - PLIST_UINT8, - PLIST_UINT16, - PLIST_UINT32, - PLIST_UINT64, - PLIST_FLOAT32, - PLIST_FLOAT64, - PLIST_STRING, - PLIST_UNICODE, - PLIST_ARRAY, - PLIST_DICT, - PLIST_DATE, - PLIST_DATA, - PLIST_PLIST, - PLIST_KEY, -} plist_type; -*/ - typedef enum { PLIST_BOOLEAN, PLIST_UINT, @@ -65,7 +43,6 @@ typedef enum { PLIST_DICT, PLIST_DATE, PLIST_DATA, - PLIST_PLIST, PLIST_KEY, } plist_type; -- cgit v1.1-32-gdbae From cd95e9bc6e23949b5cef3996132b79bd8803467a Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Wed, 10 Dec 2008 23:42:21 +0100 Subject: fix minor programming erro plus enhance plutil to convert bin to xml and xml to bin. --- dev/plutil.c | 29 +++++++++++++---------------- src/plist.c | 8 ++++---- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index 4a34077..e76506e 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -18,8 +18,6 @@ int main(int argc, char *argv[]) Options *options = parse_arguments(argc, argv); int argh = 0; - printf("plistutil version 0.2 written by FxChiP\n"); - if (!options) { print_usage(); return 0; @@ -31,26 +29,25 @@ int main(int argc, char *argv[]) stat(options->in_file, filestats); - printf("here?\n"); char *bplist_entire = (char *) malloc(sizeof(char) * (filestats->st_size + 1)); - //argh = fgets(bplist_entire, filestats->st_size, bplist); argh = fread(bplist_entire, sizeof(char), filestats->st_size, bplist); - printf("read %i bytes\n", argh); fclose(bplist); - printf("or here?\n"); // bplist_entire contains our stuff + plist_t root_node = NULL; - bin_to_plist(bplist_entire, filestats->st_size, &root_node); - printf("plutil debug mode\n\n"); - printf("file size %i\n\n", (int) filestats->st_size); - if (!root_node) { - printf("Invalid binary plist (or some other error occurred.)\n"); - return 0; - } - char *plist_xml = NULL; + char *plist_out = NULL; int size = 0; - plist_to_xml(root_node, &plist_xml, &size); - printf("%s\n", plist_xml); + + if (memcmp(bplist_entire, "bplist00", 8) == 0) { + bin_to_plist(bplist_entire, filestats->st_size, &root_node); + plist_to_xml(root_node, &plist_out, &size); + } else { + xml_to_plist(bplist_entire, filestats->st_size, &root_node); + plist_to_bin(root_node, &plist_out, &size); + } + + + printf("%s\n", plist_out); return 0; } diff --git a/src/plist.c b/src/plist.c index 431c64a..2a6d4bc 100644 --- a/src/plist.c +++ b/src/plist.c @@ -1014,16 +1014,16 @@ guint plist_data_hash(gconstpointer key) case PLIST_REAL: buff = (char *) &data->intval; size = 8; - + break; case PLIST_KEY: case PLIST_STRING: buff = data->strval; size = strlen(buff); - + break; case PLIST_UNICODE: buff = data->unicodeval; size = strlen(buff) * sizeof(wchar_t); - + break; case PLIST_DATA: case PLIST_ARRAY: case PLIST_DICT: @@ -1267,7 +1267,7 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) uint8_t *buff = NULL; uint8_t size = 0; uint64_t offsets[num_objects]; - for (i = 0; i <= num_objects; i++) { + for (i = 0; i < num_objects; i++) { offsets[i] = bplist_buff->len; struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; -- cgit v1.1-32-gdbae From 18d1ee3b0f17325fdffe0cf3e2770a3f0f45a1b9 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 11 Dec 2008 23:03:21 +0100 Subject: move stuff around to make code more organized. --- src/Makefile.am | 4 +- src/initconf.c | 30 +- src/lockdown.c | 27 -- src/lockdown.h | 2 - src/plist.c | 1118 +------------------------------------------------------ src/plist.h | 15 + 6 files changed, 53 insertions(+), 1143 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 785aacf..82fd924 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,10 +6,10 @@ AM_LDFLAGS = $(libxml2_LIBS) $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $ bin_PROGRAMS = libiphone-initconf -libiphone_initconf_SOURCES = initconf.c userpref.c lockdown.c plist.c usbmux.c iphone.c utils.c +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 lockdown.c AFC.c userpref.c utils.c +libiphone_la_SOURCES = usbmux.c iphone.c plist.c bplist.c xplist.c lockdown.c AFC.c userpref.c utils.c diff --git a/src/initconf.c b/src/initconf.c index 8aca2a6..00d78e2 100644 --- a/src/initconf.c +++ b/src/initconf.c @@ -28,7 +28,6 @@ #include "libiphone/libiphone.h" #include "userpref.h" -#include "lockdown.h" #include "utils.h" /** Generates a 2048 byte key, split into a function so that it can be run in a @@ -60,6 +59,35 @@ void progress_bar(gpointer mutex) 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; diff --git a/src/lockdown.c b/src/lockdown.c index ae077b7..0957fa2 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -39,34 +39,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { {0, 0, 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; -} /** Creates a lockdownd client for the give iPhone. * diff --git a/src/lockdown.h b/src/lockdown.h index 9176524..b75d4bf 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -40,8 +40,6 @@ struct iphone_lckd_client_int { int gtls_buffer_hack_len; }; -char *lockdownd_generate_hostid(); - 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, char **value); diff --git a/src/plist.c b/src/plist.c index 2a6d4bc..76ae954 100644 --- a/src/plist.c +++ b/src/plist.c @@ -28,101 +28,6 @@ #include #include -/********************************************** -* * -* Abstract Plist stuff * -* * -**********************************************/ - - - - - - - -/** Formats a block of text to be a given indentation and width. - * - * The total width of the return string will be depth + cols. - * - * @param buf The string to format. - * @param cols The number of text columns for returned block of text. - * @param depth The number of tabs to indent the returned block of text. - * - * @return The formatted string. - */ -char *format_string(const char *buf, int cols, int depth) -{ - int colw = depth + cols + 1; - int len = strlen(buf); - int nlines = len / cols + 1; - char *new_buf = (char *) malloc(nlines * colw + depth + 1); - int i = 0; - int j = 0; - - assert(cols >= 0); - assert(depth >= 0); - - // Inserts new lines and tabs at appropriate locations - for (i = 0; i < nlines; i++) { - new_buf[i * colw] = '\n'; - for (j = 0; j < depth; j++) - new_buf[i * colw + 1 + j] = '\t'; - memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols); - } - new_buf[len + (1 + depth) * nlines] = '\n'; - - // Inserts final row of indentation and termination character - for (j = 0; j < depth; j++) - new_buf[len + (1 + depth) * nlines + 1 + j] = '\t'; - new_buf[len + (1 + depth) * nlines + depth + 1] = '\0'; - - return new_buf; -} - - - - -/* - * Binary propertylist code follows - */ - - -/* - * This is how parsing a bplist is going to have to work: - * - The entire binary plist is going to have to be in memory. - * - A function, parse_nodes(), will have to be a recursive function - * which iterates over the binary plist and reads in elements into bplist_node structs - * and handles them accordingly. The end result should be a somewhat-hierarchical layout - * of bplist_nodes. - * - parse_nodes() will return the first node it encounters, which is usually the "root" node. - */ - - - -void print_bytes(char *val, size_t size) -{ - int i = 0; - for (i = 0; i < size; i++) { - printf("Byte %i: 0x%x\n", i, val[i]); - } -} - - - -struct plist_data { - union { - char boolval; - uint64_t intval; - double realval; - char *strval; - wchar_t *unicodeval; - char *buff; - }; - uint64_t length; - plist_type type; -}; - - void plist_new_plist(plist_t * plist) { @@ -205,683 +110,6 @@ void plist_free(plist_t plist) g_node_destroy(plist); } -/********************************************** -* * -* Xml Plist stuff * -* * -**********************************************/ - -#include -#include - - -const char *plist_base = "\n\ -\n\ -\n\ -\0"; - -struct xml_node { - xmlNodePtr xml; - uint32_t depth; -}; - -/** Creates a new plist XML document. - * - * @return The plist XML document. - */ -xmlDocPtr new_plist() -{ - char *plist = strdup(plist_base); - xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); - - if (!plist_xml) - return NULL; - - free(plist); - - return plist_xml; -} - -/** Destroys a previously created XML document. - * - * @param plist The XML document to destroy. - */ -void free_plist(xmlDocPtr plist) -{ - if (!plist) - return; - - xmlFreeDoc(plist); -} - -void node_to_xml(GNode * node, gpointer xml_struct) -{ - if (!node) - return; - - struct xml_node *xstruct = (struct xml_node *) xml_struct; - struct plist_data *node_data = (struct plist_data *) node->data; - - xmlNodePtr child_node = NULL; - char isStruct = FALSE; - - gchar *tag = NULL; - gchar *val = NULL; - - switch (node_data->type) { - case PLIST_BOOLEAN: - { - if (node_data->boolval) - tag = "true"; - else - tag = "false"; - } - break; - - case PLIST_UINT: - tag = "integer"; - val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); - break; - - case PLIST_REAL: - tag = "real"; - val = g_strdup_printf("%Lf", (long double) node_data->realval); - break; - - case PLIST_STRING: - tag = "string"; - val = g_strdup(node_data->strval); - break; - - case PLIST_UNICODE: - tag = "string"; - val = g_strdup((gchar *) node_data->unicodeval); - break; - - case PLIST_KEY: - tag = "key"; - val = g_strdup((gchar *) node_data->strval); - break; - - case PLIST_DATA: - tag = "data"; - val = format_string(node_data->buff, 60, xstruct->depth); - break; - case PLIST_ARRAY: - tag = "array"; - isStruct = TRUE; - break; - case PLIST_DICT: - tag = "dict"; - isStruct = TRUE; - break; - case PLIST_DATE: //TODO : handle date tag - default: - break; - } - - int i = 0; - for (i = 0; i < xstruct->depth; i++) { - xmlNodeAddContent(xstruct->xml, "\t"); - } - child_node = xmlNewChild(xstruct->xml, NULL, tag, val); - xmlNodeAddContent(xstruct->xml, "\n"); - g_free(val); - - //add return for structured types - if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) - xmlNodeAddContent(child_node, "\n"); - - if (isStruct) { - struct xml_node child = { child_node, xstruct->depth + 1 }; - g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); - } - //fix indent for structured types - if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { - - for (i = 0; i < xstruct->depth; i++) { - xmlNodeAddContent(child_node, "\t"); - } - } - - return; -} - -void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) -{ - xmlNodePtr node = NULL; - - for (node = xml_node->children; node; node = node->next) { - - while (node && !xmlStrcmp(node->name, "text")) - node = node->next; - if (!node) - break; - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - GNode *subnode = g_node_new(data); - g_node_append(plist_node, subnode); - - if (!xmlStrcmp(node->name, "true")) { - data->boolval = 1; - data->type = PLIST_BOOLEAN; - continue; - } - - if (!xmlStrcmp(node->name, "false")) { - data->boolval = 0; - data->type = PLIST_BOOLEAN; - continue; - } - - if (!xmlStrcmp(node->name, "integer")) { - char *strval = xmlNodeGetContent(node); - data->intval = atoi(strval); - data->type = PLIST_UINT; - continue; - } - - if (!xmlStrcmp(node->name, "real")) { - char *strval = xmlNodeGetContent(node); - data->realval = atof(strval); - data->type = PLIST_REAL; - continue; - } - - if (!xmlStrcmp(node->name, "date")) - continue; //TODO : handle date tag - - if (!xmlStrcmp(node->name, "string")) { - data->strval = strdup(xmlNodeGetContent(node)); - data->type = PLIST_STRING; - continue; - } - - if (!xmlStrcmp(node->name, "key")) { - data->strval = strdup(xmlNodeGetContent(node)); - data->type = PLIST_KEY; - continue; - } - - if (!xmlStrcmp(node->name, "data")) { - data->buff = strdup(xmlNodeGetContent(node)); - data->type = PLIST_DATA; - continue; - } - - if (!xmlStrcmp(node->name, "array")) { - data->type = PLIST_ARRAY; - xml_to_node(node, subnode); - continue; - } - - if (!xmlStrcmp(node->name, "dict")) { - data->type = PLIST_DICT; - xml_to_node(node, subnode); - continue; - } - } -} - -void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) -{ - if (!plist || !plist_xml || *plist_xml) - return; - xmlDocPtr plist_doc = new_plist(); - xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - struct xml_node root = { root_node, 0 }; - g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); - xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); -} - -void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) -{ - xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); - xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - *plist = g_node_new(data); - data->type = PLIST_DICT; - xml_to_node(root_node, *plist); -} - - - -/********************************************** -* * -* Binary Plist stuff * -* * -**********************************************/ - -/* Magic marker and size. */ -#define BPLIST_MAGIC "bplist" -#define BPLIST_MAGIC_SIZE 6 - -#define BPLIST_VERSION "00" -#define BPLIST_VERSION_SIZE 2 - - -#define BPLIST_TRL_SIZE 26 -#define BPLIST_TRL_OFFSIZE_IDX 0 -#define BPLIST_TRL_PARMSIZE_IDX 1 -#define BPLIST_TRL_NUMOBJ_IDX 2 -#define BPLIST_TRL_ROOTOBJ_IDX 10 -#define BPLIST_TRL_OFFTAB_IDX 18 - -enum { - BPLIST_NULL = 0x00, - BPLIST_TRUE = 0x08, - BPLIST_FALSE = 0x09, - BPLIST_FILL = 0x0F, /* will be used for length grabbing */ - BPLIST_UINT = 0x10, - BPLIST_REAL = 0x20, - BPLIST_DATE = 0x30, - BPLIST_DATA = 0x40, - BPLIST_STRING = 0x50, - BPLIST_UNICODE = 0x60, - BPLIST_UID = 0x70, - BPLIST_ARRAY = 0xA0, - BPLIST_SET = 0xC0, - BPLIST_DICT = 0xD0, - BPLIST_MASK = 0xF0 -}; - -void byte_convert(char *address, size_t size) -{ - int i = 0, j = 0; - char tmp = '\0'; - - for (i = 0; i < (size / 2); i++) { - tmp = address[i]; - j = ((size - 1) + 0) - i; - address[i] = address[j]; - address[j] = tmp; - } -} - -#include -#define swap_n_bytes(x, n) \ - n == 8 ? bswap_64(*(uint64_t *)(x)) : \ - (n == 4 ? bswap_32(*(uint32_t *)(x)) : \ - (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) )) - -#define be64dec(x) bswap_64( *(uint64_t*)(x) ) - -#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8))) -#define get_real_bytes(x) (x >> 32 ? 4 : 8) - -GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - size = 1 << size; // make length less misleading - switch (size) { - case sizeof(uint8_t): - data->intval = bnode[0]; - break; - case sizeof(uint16_t): - memcpy(&data->intval, bnode, size); - data->intval = ntohs(data->intval); - break; - case sizeof(uint32_t): - memcpy(&data->intval, bnode, size); - data->intval = ntohl(data->intval); - break; - case sizeof(uint64_t): - memcpy(&data->intval, bnode, size); - byte_convert((char *) &data->intval, size); - break; - default: - free(data); - return NULL; - }; - - *next_object = bnode + size; - data->type = PLIST_UINT; - return g_node_new(data); -} - -GNode *parse_real_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - size = 1 << size; // make length less misleading - switch (size) { - case sizeof(float): - memcpy(&data->realval, bnode, size); - byte_convert((char *) &data->realval, size); - break; - case sizeof(double): - memcpy(&data->realval, bnode, size); - byte_convert((char *) &data->realval, size); - break; - default: - free(data); - return NULL; - } - data->type = PLIST_REAL; - return g_node_new(data); -} - -GNode *parse_string_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_STRING; - data->strval = (char *) malloc(sizeof(char) * (size + 1)); - memcpy(data->strval, bnode, size); - data->strval[size] = '\0'; - - return g_node_new(data); -} - -GNode *parse_unicode_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_UNICODE; - data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1)); - memcpy(data->unicodeval, bnode, size); - data->unicodeval[size] = '\0'; - - return g_node_new(data); -} - -GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_DATA; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size); - memcpy(data->buff, bnode, sizeof(char) * size); - - return g_node_new(data); -} - -GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_DICT; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2); - memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2); - - return g_node_new(data); -} - -GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_ARRAY; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size * ref_size); - memcpy(data->buff, bnode, sizeof(char) * size * ref_size); - - return g_node_new(data); -} - -plist_type plist_get_node_type(plist_t node) -{ - return ((struct plist_data *) node->data)->type; -} - -uint64_t plist_get_node_uint_val(plist_t node) -{ - if (PLIST_UINT == plist_get_node_type(node)) - return ((struct plist_data *) node->data)->intval; - else - return 0; -} - -GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) -{ - if (!object) - return NULL; - - uint16_t type = *object & 0xF0; - uint64_t size = *object & 0x0F; - object++; - - switch (type) { - - case BPLIST_NULL: - switch (size) { - - case BPLIST_TRUE: - { - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_BOOLEAN; - data->boolval = TRUE; - return g_node_new(data); - } - - case BPLIST_FALSE: - { - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_BOOLEAN; - data->boolval = FALSE; - return g_node_new(data); - } - - case BPLIST_NULL: - default: - return NULL; - } - - case BPLIST_UINT: - return parse_uint_node(object, size, next_object); - - case BPLIST_REAL: - return parse_real_node(object, size); - - case BPLIST_DATE: - if (3 != size) - return NULL; - else - return parse_real_node(object, size); - - case BPLIST_DATA: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_data_node(object, size, dict_size); - - case BPLIST_STRING: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_string_node(object, size); - - case BPLIST_UNICODE: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_unicode_node(object, size); - - case BPLIST_UID: - case BPLIST_ARRAY: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_array_node(object, size, dict_size); - - case BPLIST_SET: - case BPLIST_DICT: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - object++; - size = plist_get_node_uint_val(size_node); - } - return parse_dict_node(object, size, dict_size); - - } - return NULL; -} - -gpointer copy_plist_data(gconstpointer src, gpointer data) -{ - struct plist_data *srcdata = (struct plist_data *) src; - struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - dstdata->type = srcdata->type; - dstdata->length = srcdata->length; - switch (dstdata->type) { - case PLIST_BOOLEAN: - dstdata->boolval = srcdata->boolval; - break; - case PLIST_UINT: - dstdata->intval = srcdata->intval; - break; - case PLIST_DATE: - case PLIST_REAL: - dstdata->realval = srcdata->realval; - break; - case PLIST_KEY: - case PLIST_STRING: - dstdata->strval = strdup(srcdata->strval); - break; - case PLIST_UNICODE: - dstdata->unicodeval = wcsdup(srcdata->unicodeval); - break; - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length); - memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length); - break; - - default: - break; - } - - return dstdata; -} - -void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) -{ - //first check we have enough data - if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) - return; - //check that plist_bin in actually a plist - if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) - return; - //check for known version - if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) - return; - - //now parse trailer - const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); - - uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; - uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; - uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); - uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); - uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); - - log_debug_msg("Offset size: %i\n", offset_size); - log_debug_msg("Ref size: %i\n", dict_param_size); - log_debug_msg("Number of objects: %lli\n", num_objects); - log_debug_msg("Root object index: %lli\n", root_object); - log_debug_msg("Offset table index: %lli\n", offset_table_index); - - if (num_objects == 0) - return; - - //allocate serialized array of nodes - plist_t *nodeslist = NULL; - nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); - - if (!nodeslist) - return; - - //parse serialized nodes - uint64_t i = 0; - uint64_t current_offset = 0; - const char *offset_table = plist_bin + offset_table_index; - for (i = 0; i < num_objects; i++) { - current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size); - - log_debug_msg("parse_nodes: current_offset = %i\n", current_offset); - char *obj = plist_bin + current_offset; - nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); - log_debug_msg("parse_nodes: parse_raw_node done\n"); - } - - //setup children for structured types - int j = 0, str_i = 0, str_j = 0; - uint32_t index1 = 0, index2 = 0; - - for (i = 0; i < num_objects; i++) { - - log_debug_msg("parse_nodes: on node %i\n", i); - struct plist_data *data = (struct plist_data *) nodeslist[i]->data; - - switch (data->type) { - case PLIST_DICT: - log_debug_msg("parse_nodes: dictionary found\n"); - for (j = 0; j < data->length; j++) { - str_i = j * dict_param_size; - str_j = (j + data->length) * dict_param_size; - - index1 = swap_n_bytes(data->buff + str_i, dict_param_size); - index2 = swap_n_bytes(data->buff + str_j, dict_param_size); - - //first one is actually a key - ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; - - if (G_NODE_IS_ROOT(nodeslist[index1])) - g_node_append(nodeslist[i], nodeslist[index1]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); - - if (G_NODE_IS_ROOT(nodeslist[index2])) - g_node_append(nodeslist[i], nodeslist[index2]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL)); - } - - free(data->buff); - break; - - case PLIST_ARRAY: - log_debug_msg("parse_nodes: array found\n"); - for (j = 0; j < data->length; j++) { - str_j = j * dict_param_size; - index1 = swap_n_bytes(data->buff + str_j, dict_param_size); - - //g_node_append(nodeslist[i], nodeslist[index1]); - if (G_NODE_IS_ROOT(nodeslist[index1])) - g_node_append(nodeslist[i], nodeslist[index1]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); - } - free(data->buff); - break; - default: - break; - } - } - - *plist = nodeslist[root_object]; -} - GNode *find_query_node(plist_t plist, char *key, char *request) { if (!plist) @@ -998,347 +226,15 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) } } -guint plist_data_hash(gconstpointer key) -{ - struct plist_data *data = (struct plist_data *) ((GNode *) key)->data; - - guint hash = data->type; - guint i = 0; - - char *buff = NULL; - guint size = 0; - - switch (data->type) { - case PLIST_BOOLEAN: - case PLIST_UINT: - case PLIST_REAL: - buff = (char *) &data->intval; - size = 8; - break; - case PLIST_KEY: - case PLIST_STRING: - buff = data->strval; - size = strlen(buff); - break; - case PLIST_UNICODE: - buff = data->unicodeval; - size = strlen(buff) * sizeof(wchar_t); - break; - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - //for these types only hash pointer - buff = &key; - size = sizeof(gconstpointer); - break; - case PLIST_DATE: - default: - break; - } - - //now perform hash - for (i = 0; i < size; buff++, i++) - hash = hash << 7 ^ (*buff); - - return hash; -} - -gboolean plist_data_compare(gconstpointer a, gconstpointer b) -{ - if (!a || !b) - return FALSE; - - if (!((GNode *) a)->data || !((GNode *) b)->data) - return FALSE; - - struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data; - struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data; - - if (val_a->type != val_b->type) - return FALSE; - - switch (val_a->type) { - case PLIST_BOOLEAN: - case PLIST_UINT: - case PLIST_REAL: - if (val_a->intval == val_b->intval) //it is an union so this is sufficient - return TRUE; - else - return FALSE; - - case PLIST_KEY: - case PLIST_STRING: - if (!strcmp(val_a->strval, val_b->strval)) - return TRUE; - else - return FALSE; - case PLIST_UNICODE: - if (!strcmp(val_a->unicodeval, val_b->unicodeval)) - return TRUE; - else - return FALSE; - - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - //compare pointer - if (a == b) - return TRUE; - else - return FALSE; - break; - case PLIST_DATE: - default: - break; - } - return FALSE; -} - -struct serialize_s { - GPtrArray *objects; - GHashTable *ref_table; -}; - -void serialize_plist(GNode * node, gpointer data) -{ - struct serialize_s *ser = (struct serialize_s *) data; - uint64_t current_index = ser->objects->len; - - //first check that node is not yet in objects - gpointer val = g_hash_table_lookup(ser->ref_table, node); - if (val) { - //data is already in table - return; - } - //insert new ref - g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index)); - - //now append current node to object array - g_ptr_array_add(ser->objects, node); - - //now recurse on children - g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data); - return; -} - - - -void write_int(GByteArray * bplist, uint64_t val) -{ - uint64_t size = get_needed_bytes(val); - uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_UINT | size >> 1; - memcpy(buff + 1, &val, size); - swap_n_bytes(buff + 1, size); - g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); - free(buff); -} - -void write_real(GByteArray * bplist, double val) -{ - uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space - uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_REAL | size >> 1; - memcpy(buff + 1, &val, size); - swap_n_bytes(buff + 1, size); - g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); - free(buff); -} - -void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) -{ - uint8_t marker = mark | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - uint8_t *buff = (uint8_t *) malloc(size); - memcpy(buff, val, size); - g_byte_array_append(bplist, buff, size); - free(buff); -} - -void write_data(GByteArray * bplist, uint8_t * val, uint64_t size) -{ - write_raw_data(bplist, BPLIST_DATA, val, size); -} - -void write_string(GByteArray * bplist, char *val) -{ - uint64_t size = strlen(val); - write_raw_data(bplist, BPLIST_STRING, val, size); -} - -void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) -{ - uint64_t size = g_node_n_children(node); - uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - - uint64_t idx = 0; - uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); - - GNode *cur = NULL; - int i = 0; - for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { - idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); - memcpy(buff + i * dict_param_size, &idx, dict_param_size); - swap_n_bytes(buff + i * dict_param_size, dict_param_size); - } - - //now append to bplist - g_byte_array_append(bplist, buff, size * dict_param_size); - free(buff); - -} - -void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) +plist_type plist_get_node_type(plist_t node) { - uint64_t size = g_node_n_children(node) / 2; - uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - - uint64_t idx1 = 0; - uint64_t idx2 = 0; - uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); - - GNode *cur = NULL; - int i = 0; - for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { - idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); - memcpy(buff + i * dict_param_size, &idx1, dict_param_size); - swap_n_bytes(buff + i * dict_param_size, dict_param_size); - - idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); - memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); - swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size); - } - - //now append to bplist - g_byte_array_append(bplist, buff, size * dict_param_size); - free(buff); - + return ((struct plist_data *) node->data)->type; } -void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) +uint64_t plist_get_node_uint_val(plist_t node) { - //first serialize tree - - //list of objects - GPtrArray *objects = g_ptr_array_new(); - //hashtable to write only once same nodes - GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); - - //serialize plist - struct serialize_s ser_s = { objects, ref_table }; - g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s); - - //now stream to output buffer - uint8_t offset_size = 0; //unknown yet - uint8_t dict_param_size = get_needed_bytes(objects->len); - uint64_t num_objects = objects->len; - uint64_t root_object = 0; //root is first in list - uint64_t offset_table_index = 0; //unknown yet - - //setup a dynamic bytes array to store bplist in - GByteArray *bplist_buff = g_byte_array_new(); - - //set magic number and version - g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); - g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); - - //write objects and table - int i = 0; - uint8_t *buff = NULL; - uint8_t size = 0; - uint64_t offsets[num_objects]; - for (i = 0; i < num_objects; i++) { - - offsets[i] = bplist_buff->len; - struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; - - switch (data->type) { - case PLIST_BOOLEAN: - buff = (uint8_t *) malloc(sizeof(uint8_t)); - buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE; - g_byte_array_append(bplist_buff, buff, sizeof(uint8_t)); - free(buff); - break; - - case PLIST_UINT: - write_int(bplist_buff, data->intval); - break; - - case PLIST_REAL: - write_real(bplist_buff, data->realval); - break; - - case PLIST_KEY: - case PLIST_STRING: - write_string(bplist_buff, data->strval); - break; - case PLIST_UNICODE: - //TODO - break; - case PLIST_DATA: - write_data(bplist_buff, data->strval, data->length); - case PLIST_ARRAY: - write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); - break; - case PLIST_DICT: - write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); - break; - case PLIST_DATE: - //TODO - break; - default: - break; - } - } - - //write offsets - offset_size = get_needed_bytes(bplist_buff->len); - for (i = 0; i <= num_objects; i++) { - uint8_t *buff = (uint8_t *) malloc(offset_size); - memcpy(buff, offsets + i, offset_size); - swap_n_bytes(buff, offset_size); - g_byte_array_append(bplist_buff, buff, offset_size); - free(buff); - } - - //setup trailer - num_objects = bswap_64(num_objects); - root_object = bswap_64(root_object); - offset_table_index = bswap_64(offset_table_index); - - char trailer[BPLIST_TRL_SIZE]; - memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); - memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); - memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); - memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t)); - memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t)); - - g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE); - - //duplicate buffer - *plist_bin = (char *) malloc(bplist_buff->len); - memcpy(*plist_bin, bplist_buff->data, bplist_buff->len); - *length = bplist_buff->len; - - g_byte_array_free(bplist_buff, TRUE); + if (PLIST_UINT == plist_get_node_type(node)) + return ((struct plist_data *) node->data)->intval; + else + return 0; } diff --git a/src/plist.h b/src/plist.h index 63f67f7..e3f3f59 100644 --- a/src/plist.h +++ b/src/plist.h @@ -47,6 +47,20 @@ typedef enum { } plist_type; +struct plist_data { + union { + char boolval; + uint64_t intval; + double realval; + char *strval; + wchar_t *unicodeval; + char *buff; + }; + uint64_t length; + plist_type type; +}; + + typedef GNode *plist_t; typedef GNode *dict_t; @@ -67,4 +81,5 @@ void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); GNode *find_query_node(plist_t plist, char *key, char *request); GNode *find_node(plist_t plist, plist_type type, void *value); void get_type_and_value(GNode * node, plist_type * type, void *value); + #endif -- cgit v1.1-32-gdbae From 31379321cec6bf6c6d670e0738d1b1e23dc92ac1 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 11 Dec 2008 23:05:29 +0100 Subject: dissect plists in three file (abstract binary xml) --- src/bplist.c | 790 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xplist.c | 306 +++++++++++++++++++++++ 2 files changed, 1096 insertions(+) create mode 100644 src/bplist.c create mode 100644 src/xplist.c diff --git a/src/bplist.c b/src/bplist.c new file mode 100644 index 0000000..6136fe9 --- /dev/null +++ b/src/bplist.c @@ -0,0 +1,790 @@ +/* + * plist.c + * Binary plist implementation + * + * 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 "plist.h" +#include +#include +#include +#include + +/* Magic marker and size. */ +#define BPLIST_MAGIC "bplist" +#define BPLIST_MAGIC_SIZE 6 + +#define BPLIST_VERSION "00" +#define BPLIST_VERSION_SIZE 2 + + +#define BPLIST_TRL_SIZE 26 +#define BPLIST_TRL_OFFSIZE_IDX 0 +#define BPLIST_TRL_PARMSIZE_IDX 1 +#define BPLIST_TRL_NUMOBJ_IDX 2 +#define BPLIST_TRL_ROOTOBJ_IDX 10 +#define BPLIST_TRL_OFFTAB_IDX 18 + +enum { + BPLIST_NULL = 0x00, + BPLIST_TRUE = 0x08, + BPLIST_FALSE = 0x09, + BPLIST_FILL = 0x0F, /* will be used for length grabbing */ + BPLIST_UINT = 0x10, + BPLIST_REAL = 0x20, + BPLIST_DATE = 0x30, + BPLIST_DATA = 0x40, + BPLIST_STRING = 0x50, + BPLIST_UNICODE = 0x60, + BPLIST_UID = 0x70, + BPLIST_ARRAY = 0xA0, + BPLIST_SET = 0xC0, + BPLIST_DICT = 0xD0, + BPLIST_MASK = 0xF0 +}; + +void byte_convert(char *address, size_t size) +{ + int i = 0, j = 0; + char tmp = '\0'; + + for (i = 0; i < (size / 2); i++) { + tmp = address[i]; + j = ((size - 1) + 0) - i; + address[i] = address[j]; + address[j] = tmp; + } +} + +#include +#define swap_n_bytes(x, n) \ + n == 8 ? bswap_64(*(uint64_t *)(x)) : \ + (n == 4 ? bswap_32(*(uint32_t *)(x)) : \ + (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) )) + +#define be64dec(x) bswap_64( *(uint64_t*)(x) ) + +#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8))) +#define get_real_bytes(x) (x >> 32 ? 4 : 8) + +GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + size = 1 << size; // make length less misleading + switch (size) { + case sizeof(uint8_t): + data->intval = bnode[0]; + break; + case sizeof(uint16_t): + memcpy(&data->intval, bnode, size); + data->intval = ntohs(data->intval); + break; + case sizeof(uint32_t): + memcpy(&data->intval, bnode, size); + data->intval = ntohl(data->intval); + break; + case sizeof(uint64_t): + memcpy(&data->intval, bnode, size); + byte_convert((char *) &data->intval, size); + break; + default: + free(data); + return NULL; + }; + + *next_object = bnode + size; + data->type = PLIST_UINT; + return g_node_new(data); +} + +GNode *parse_real_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + size = 1 << size; // make length less misleading + switch (size) { + case sizeof(float): + memcpy(&data->realval, bnode, size); + byte_convert((char *) &data->realval, size); + break; + case sizeof(double): + memcpy(&data->realval, bnode, size); + byte_convert((char *) &data->realval, size); + break; + default: + free(data); + return NULL; + } + data->type = PLIST_REAL; + return g_node_new(data); +} + +GNode *parse_string_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_STRING; + data->strval = (char *) malloc(sizeof(char) * (size + 1)); + memcpy(data->strval, bnode, size); + data->strval[size] = '\0'; + + return g_node_new(data); +} + +GNode *parse_unicode_node(char *bnode, uint8_t size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_UNICODE; + data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1)); + memcpy(data->unicodeval, bnode, size); + data->unicodeval[size] = '\0'; + + return g_node_new(data); +} + +GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_DATA; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size); + memcpy(data->buff, bnode, sizeof(char) * size); + + return g_node_new(data); +} + +GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_DICT; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2); + memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2); + + return g_node_new(data); +} + +GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) +{ + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + data->type = PLIST_ARRAY; + data->length = size; + data->buff = (char *) malloc(sizeof(char) * size * ref_size); + memcpy(data->buff, bnode, sizeof(char) * size * ref_size); + + return g_node_new(data); +} + + + +GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) +{ + if (!object) + return NULL; + + uint16_t type = *object & 0xF0; + uint64_t size = *object & 0x0F; + object++; + + switch (type) { + + case BPLIST_NULL: + switch (size) { + + case BPLIST_TRUE: + { + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + data->type = PLIST_BOOLEAN; + data->boolval = TRUE; + return g_node_new(data); + } + + case BPLIST_FALSE: + { + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + data->type = PLIST_BOOLEAN; + data->boolval = FALSE; + return g_node_new(data); + } + + case BPLIST_NULL: + default: + return NULL; + } + + case BPLIST_UINT: + return parse_uint_node(object, size, next_object); + + case BPLIST_REAL: + return parse_real_node(object, size); + + case BPLIST_DATE: + if (3 != size) + return NULL; + else + return parse_real_node(object, size); + + case BPLIST_DATA: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_data_node(object, size, dict_size); + + case BPLIST_STRING: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_string_node(object, size); + + case BPLIST_UNICODE: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_unicode_node(object, size); + + case BPLIST_UID: + case BPLIST_ARRAY: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + size = plist_get_node_uint_val(size_node); + } + return parse_array_node(object, size, dict_size); + + case BPLIST_SET: + case BPLIST_DICT: + if (0x0F == size) { + plist_t size_node = parse_bin_node(object, dict_size, &object); + if (plist_get_node_type(size_node) != PLIST_UINT) + return NULL; + object++; + size = plist_get_node_uint_val(size_node); + } + return parse_dict_node(object, size, dict_size); + + } + return NULL; +} + +gpointer copy_plist_data(gconstpointer src, gpointer data) +{ + struct plist_data *srcdata = (struct plist_data *) src; + struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + + dstdata->type = srcdata->type; + dstdata->length = srcdata->length; + switch (dstdata->type) { + case PLIST_BOOLEAN: + dstdata->boolval = srcdata->boolval; + break; + case PLIST_UINT: + dstdata->intval = srcdata->intval; + break; + case PLIST_DATE: + case PLIST_REAL: + dstdata->realval = srcdata->realval; + break; + case PLIST_KEY: + case PLIST_STRING: + dstdata->strval = strdup(srcdata->strval); + break; + case PLIST_UNICODE: + dstdata->unicodeval = wcsdup(srcdata->unicodeval); + break; + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length); + memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length); + break; + + default: + break; + } + + return dstdata; +} + +void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) +{ + //first check we have enough data + if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) + return; + //check that plist_bin in actually a plist + if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) + return; + //check for known version + if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) + return; + + //now parse trailer + const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); + + uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; + uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; + uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); + uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); + uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); + + log_debug_msg("Offset size: %i\n", offset_size); + log_debug_msg("Ref size: %i\n", dict_param_size); + log_debug_msg("Number of objects: %lli\n", num_objects); + log_debug_msg("Root object index: %lli\n", root_object); + log_debug_msg("Offset table index: %lli\n", offset_table_index); + + if (num_objects == 0) + return; + + //allocate serialized array of nodes + plist_t *nodeslist = NULL; + nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); + + if (!nodeslist) + return; + + //parse serialized nodes + uint64_t i = 0; + uint64_t current_offset = 0; + const char *offset_table = plist_bin + offset_table_index; + for (i = 0; i < num_objects; i++) { + current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size); + + log_debug_msg("parse_nodes: current_offset = %i\n", current_offset); + char *obj = plist_bin + current_offset; + nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); + log_debug_msg("parse_nodes: parse_raw_node done\n"); + } + + //setup children for structured types + int j = 0, str_i = 0, str_j = 0; + uint32_t index1 = 0, index2 = 0; + + for (i = 0; i < num_objects; i++) { + + log_debug_msg("parse_nodes: on node %i\n", i); + struct plist_data *data = (struct plist_data *) nodeslist[i]->data; + + switch (data->type) { + case PLIST_DICT: + log_debug_msg("parse_nodes: dictionary found\n"); + for (j = 0; j < data->length; j++) { + str_i = j * dict_param_size; + str_j = (j + data->length) * dict_param_size; + + index1 = swap_n_bytes(data->buff + str_i, dict_param_size); + index2 = swap_n_bytes(data->buff + str_j, dict_param_size); + + //first one is actually a key + ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; + + if (G_NODE_IS_ROOT(nodeslist[index1])) + g_node_append(nodeslist[i], nodeslist[index1]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); + + if (G_NODE_IS_ROOT(nodeslist[index2])) + g_node_append(nodeslist[i], nodeslist[index2]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL)); + } + + free(data->buff); + break; + + case PLIST_ARRAY: + log_debug_msg("parse_nodes: array found\n"); + for (j = 0; j < data->length; j++) { + str_j = j * dict_param_size; + index1 = swap_n_bytes(data->buff + str_j, dict_param_size); + + //g_node_append(nodeslist[i], nodeslist[index1]); + if (G_NODE_IS_ROOT(nodeslist[index1])) + g_node_append(nodeslist[i], nodeslist[index1]); + else + g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); + } + free(data->buff); + break; + default: + break; + } + } + + *plist = nodeslist[root_object]; +} + +guint plist_data_hash(gconstpointer key) +{ + struct plist_data *data = (struct plist_data *) ((GNode *) key)->data; + + guint hash = data->type; + guint i = 0; + + char *buff = NULL; + guint size = 0; + + switch (data->type) { + case PLIST_BOOLEAN: + case PLIST_UINT: + case PLIST_REAL: + buff = (char *) &data->intval; + size = 8; + break; + case PLIST_KEY: + case PLIST_STRING: + buff = data->strval; + size = strlen(buff); + break; + case PLIST_UNICODE: + buff = data->unicodeval; + size = strlen(buff) * sizeof(wchar_t); + break; + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + //for these types only hash pointer + buff = &key; + size = sizeof(gconstpointer); + break; + case PLIST_DATE: + default: + break; + } + + //now perform hash + for (i = 0; i < size; buff++, i++) + hash = hash << 7 ^ (*buff); + + return hash; +} + +gboolean plist_data_compare(gconstpointer a, gconstpointer b) +{ + if (!a || !b) + return FALSE; + + if (!((GNode *) a)->data || !((GNode *) b)->data) + return FALSE; + + struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data; + struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data; + + if (val_a->type != val_b->type) + return FALSE; + + switch (val_a->type) { + case PLIST_BOOLEAN: + case PLIST_UINT: + case PLIST_REAL: + if (val_a->intval == val_b->intval) //it is an union so this is sufficient + return TRUE; + else + return FALSE; + + case PLIST_KEY: + case PLIST_STRING: + if (!strcmp(val_a->strval, val_b->strval)) + return TRUE; + else + return FALSE; + case PLIST_UNICODE: + if (!strcmp(val_a->unicodeval, val_b->unicodeval)) + return TRUE; + else + return FALSE; + + case PLIST_DATA: + case PLIST_ARRAY: + case PLIST_DICT: + //compare pointer + if (a == b) + return TRUE; + else + return FALSE; + break; + case PLIST_DATE: + default: + break; + } + return FALSE; +} + +struct serialize_s { + GPtrArray *objects; + GHashTable *ref_table; +}; + +void serialize_plist(GNode * node, gpointer data) +{ + struct serialize_s *ser = (struct serialize_s *) data; + uint64_t current_index = ser->objects->len; + + //first check that node is not yet in objects + gpointer val = g_hash_table_lookup(ser->ref_table, node); + if (val) { + //data is already in table + return; + } + //insert new ref + g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index)); + + //now append current node to object array + g_ptr_array_add(ser->objects, node); + + //now recurse on children + g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data); + return; +} + + + +void write_int(GByteArray * bplist, uint64_t val) +{ + uint64_t size = get_needed_bytes(val); + uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); + buff[0] = BPLIST_UINT | size >> 1; + memcpy(buff + 1, &val, size); + swap_n_bytes(buff + 1, size); + g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); + free(buff); +} + +void write_real(GByteArray * bplist, double val) +{ + uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space + uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); + buff[0] = BPLIST_REAL | size >> 1; + memcpy(buff + 1, &val, size); + swap_n_bytes(buff + 1, size); + g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); + free(buff); +} + +void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) +{ + uint8_t marker = mark | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + uint8_t *buff = (uint8_t *) malloc(size); + memcpy(buff, val, size); + g_byte_array_append(bplist, buff, size); + free(buff); +} + +void write_data(GByteArray * bplist, uint8_t * val, uint64_t size) +{ + write_raw_data(bplist, BPLIST_DATA, val, size); +} + +void write_string(GByteArray * bplist, char *val) +{ + uint64_t size = strlen(val); + write_raw_data(bplist, BPLIST_STRING, val, size); +} + +void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) +{ + uint64_t size = g_node_n_children(node); + uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + + uint64_t idx = 0; + uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); + + GNode *cur = NULL; + int i = 0; + for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { + idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); + memcpy(buff + i * dict_param_size, &idx, dict_param_size); + swap_n_bytes(buff + i * dict_param_size, dict_param_size); + } + + //now append to bplist + g_byte_array_append(bplist, buff, size * dict_param_size); + free(buff); + +} + +void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) +{ + uint64_t size = g_node_n_children(node) / 2; + uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); + g_byte_array_append(bplist, &marker, sizeof(uint8_t)); + if (size >= 15) { + GByteArray *int_buff = g_byte_array_new(); + write_int(int_buff, size); + g_byte_array_append(bplist, int_buff->data, int_buff->len); + g_byte_array_free(int_buff, TRUE); + } + + uint64_t idx1 = 0; + uint64_t idx2 = 0; + uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); + + GNode *cur = NULL; + int i = 0; + for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { + idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); + memcpy(buff + i * dict_param_size, &idx1, dict_param_size); + swap_n_bytes(buff + i * dict_param_size, dict_param_size); + + idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); + memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); + swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size); + } + + //now append to bplist + g_byte_array_append(bplist, buff, size * dict_param_size); + free(buff); + +} + +void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) +{ + //first serialize tree + + //list of objects + GPtrArray *objects = g_ptr_array_new(); + //hashtable to write only once same nodes + GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); + + //serialize plist + struct serialize_s ser_s = { objects, ref_table }; + g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s); + + //now stream to output buffer + uint8_t offset_size = 0; //unknown yet + uint8_t dict_param_size = get_needed_bytes(objects->len); + uint64_t num_objects = objects->len; + uint64_t root_object = 0; //root is first in list + uint64_t offset_table_index = 0; //unknown yet + + //setup a dynamic bytes array to store bplist in + GByteArray *bplist_buff = g_byte_array_new(); + + //set magic number and version + g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); + g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); + + //write objects and table + int i = 0; + uint8_t *buff = NULL; + uint8_t size = 0; + uint64_t offsets[num_objects]; + for (i = 0; i < num_objects; i++) { + + offsets[i] = bplist_buff->len; + struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; + + switch (data->type) { + case PLIST_BOOLEAN: + buff = (uint8_t *) malloc(sizeof(uint8_t)); + buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE; + g_byte_array_append(bplist_buff, buff, sizeof(uint8_t)); + free(buff); + break; + + case PLIST_UINT: + write_int(bplist_buff, data->intval); + break; + + case PLIST_REAL: + write_real(bplist_buff, data->realval); + break; + + case PLIST_KEY: + case PLIST_STRING: + write_string(bplist_buff, data->strval); + break; + case PLIST_UNICODE: + //TODO + break; + case PLIST_DATA: + write_data(bplist_buff, data->strval, data->length); + case PLIST_ARRAY: + write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); + break; + case PLIST_DICT: + write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); + break; + case PLIST_DATE: + //TODO + break; + default: + break; + } + } + + //write offsets + offset_size = get_needed_bytes(bplist_buff->len); + for (i = 0; i <= num_objects; i++) { + uint8_t *buff = (uint8_t *) malloc(offset_size); + memcpy(buff, offsets + i, offset_size); + swap_n_bytes(buff, offset_size); + g_byte_array_append(bplist_buff, buff, offset_size); + free(buff); + } + + //setup trailer + num_objects = bswap_64(num_objects); + root_object = bswap_64(root_object); + offset_table_index = bswap_64(offset_table_index); + + char trailer[BPLIST_TRL_SIZE]; + memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); + memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); + memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); + memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t)); + memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t)); + + g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE); + + //duplicate buffer + *plist_bin = (char *) malloc(bplist_buff->len); + memcpy(*plist_bin, bplist_buff->data, bplist_buff->len); + *length = bplist_buff->len; + + g_byte_array_free(bplist_buff, TRUE); +} diff --git a/src/xplist.c b/src/xplist.c new file mode 100644 index 0000000..a87b259 --- /dev/null +++ b/src/xplist.c @@ -0,0 +1,306 @@ +/* + * plist.c + * XML plist implementation + * + * 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 "utils.h" +#include "plist.h" +#include +#include +#include + + +#include +#include + + +const char *plist_base = "\n\ +\n\ +\n\ +\0"; + + +/** Formats a block of text to be a given indentation and width. + * + * The total width of the return string will be depth + cols. + * + * @param buf The string to format. + * @param cols The number of text columns for returned block of text. + * @param depth The number of tabs to indent the returned block of text. + * + * @return The formatted string. + */ +char *format_string(const char *buf, int cols, int depth) +{ + int colw = depth + cols + 1; + int len = strlen(buf); + int nlines = len / cols + 1; + char *new_buf = (char *) malloc(nlines * colw + depth + 1); + int i = 0; + int j = 0; + + assert(cols >= 0); + assert(depth >= 0); + + // Inserts new lines and tabs at appropriate locations + for (i = 0; i < nlines; i++) { + new_buf[i * colw] = '\n'; + for (j = 0; j < depth; j++) + new_buf[i * colw + 1 + j] = '\t'; + memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols); + } + new_buf[len + (1 + depth) * nlines] = '\n'; + + // Inserts final row of indentation and termination character + for (j = 0; j < depth; j++) + new_buf[len + (1 + depth) * nlines + 1 + j] = '\t'; + new_buf[len + (1 + depth) * nlines + depth + 1] = '\0'; + + return new_buf; +} + + + +struct xml_node { + xmlNodePtr xml; + uint32_t depth; +}; + +/** Creates a new plist XML document. + * + * @return The plist XML document. + */ +xmlDocPtr new_plist() +{ + char *plist = strdup(plist_base); + xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); + + if (!plist_xml) + return NULL; + + free(plist); + + return plist_xml; +} + +/** Destroys a previously created XML document. + * + * @param plist The XML document to destroy. + */ +void free_plist(xmlDocPtr plist) +{ + if (!plist) + return; + + xmlFreeDoc(plist); +} + +void node_to_xml(GNode * node, gpointer xml_struct) +{ + if (!node) + return; + + struct xml_node *xstruct = (struct xml_node *) xml_struct; + struct plist_data *node_data = (struct plist_data *) node->data; + + xmlNodePtr child_node = NULL; + char isStruct = FALSE; + + gchar *tag = NULL; + gchar *val = NULL; + + switch (node_data->type) { + case PLIST_BOOLEAN: + { + if (node_data->boolval) + tag = "true"; + else + tag = "false"; + } + break; + + case PLIST_UINT: + tag = "integer"; + val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); + break; + + case PLIST_REAL: + tag = "real"; + val = g_strdup_printf("%Lf", (long double) node_data->realval); + break; + + case PLIST_STRING: + tag = "string"; + val = g_strdup(node_data->strval); + break; + + case PLIST_UNICODE: + tag = "string"; + val = g_strdup((gchar *) node_data->unicodeval); + break; + + case PLIST_KEY: + tag = "key"; + val = g_strdup((gchar *) node_data->strval); + break; + + case PLIST_DATA: + tag = "data"; + val = format_string(node_data->buff, 60, xstruct->depth); + break; + case PLIST_ARRAY: + tag = "array"; + isStruct = TRUE; + break; + case PLIST_DICT: + tag = "dict"; + isStruct = TRUE; + break; + case PLIST_DATE: //TODO : handle date tag + default: + break; + } + + int i = 0; + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(xstruct->xml, "\t"); + } + child_node = xmlNewChild(xstruct->xml, NULL, tag, val); + xmlNodeAddContent(xstruct->xml, "\n"); + g_free(val); + + //add return for structured types + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) + xmlNodeAddContent(child_node, "\n"); + + if (isStruct) { + struct xml_node child = { child_node, xstruct->depth + 1 }; + g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); + } + //fix indent for structured types + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { + + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(child_node, "\t"); + } + } + + return; +} + +void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) +{ + xmlNodePtr node = NULL; + + for (node = xml_node->children; node; node = node->next) { + + while (node && !xmlStrcmp(node->name, "text")) + node = node->next; + if (!node) + break; + + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + GNode *subnode = g_node_new(data); + g_node_append(plist_node, subnode); + + if (!xmlStrcmp(node->name, "true")) { + data->boolval = 1; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "false")) { + data->boolval = 0; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "integer")) { + char *strval = xmlNodeGetContent(node); + data->intval = atoi(strval); + data->type = PLIST_UINT; + continue; + } + + if (!xmlStrcmp(node->name, "real")) { + char *strval = xmlNodeGetContent(node); + data->realval = atof(strval); + data->type = PLIST_REAL; + continue; + } + + if (!xmlStrcmp(node->name, "date")) + continue; //TODO : handle date tag + + if (!xmlStrcmp(node->name, "string")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_STRING; + continue; + } + + if (!xmlStrcmp(node->name, "key")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_KEY; + continue; + } + + if (!xmlStrcmp(node->name, "data")) { + data->buff = strdup(xmlNodeGetContent(node)); + data->type = PLIST_DATA; + continue; + } + + if (!xmlStrcmp(node->name, "array")) { + data->type = PLIST_ARRAY; + xml_to_node(node, subnode); + continue; + } + + if (!xmlStrcmp(node->name, "dict")) { + data->type = PLIST_DICT; + xml_to_node(node, subnode); + continue; + } + } +} + +void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) +{ + if (!plist || !plist_xml || *plist_xml) + return; + xmlDocPtr plist_doc = new_plist(); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + struct xml_node root = { root_node, 0 }; + g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); + xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); +} + +void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) +{ + xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + *plist = g_node_new(data); + data->type = PLIST_DICT; + xml_to_node(root_node, *plist); +} -- cgit v1.1-32-gdbae From 9ca887308d59e6cb5bf684f9f3bd968118e8014f Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 12 Dec 2008 22:05:44 +0100 Subject: Fix some bugs in binary plist generation. --- dev/plutil.c | 37 +++++++++++++------- src/bplist.c | 29 +++++++++------- src/lockdown.c | 105 ++++++++++++++++++++++++++------------------------------- src/plist.c | 27 ++++++++++----- src/plist.h | 20 +++++------ src/xplist.c | 26 +++++++------- 6 files changed, 129 insertions(+), 115 deletions(-) diff --git a/dev/plutil.c b/dev/plutil.c index e76506e..3d93797 100644 --- a/dev/plutil.c +++ b/dev/plutil.c @@ -14,9 +14,7 @@ int main(int argc, char *argv[]) { struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); - uint32_t position = 0; Options *options = parse_arguments(argc, argv); - int argh = 0; if (!options) { print_usage(); @@ -25,29 +23,42 @@ int main(int argc, char *argv[]) iphone_set_debug(options->debug); - FILE *bplist = fopen(options->in_file, "r"); - + //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); - char *bplist_entire = (char *) malloc(sizeof(char) * (filestats->st_size + 1)); - argh = fread(bplist_entire, sizeof(char), filestats->st_size, bplist); - fclose(bplist); - // bplist_entire contains our stuff + //convert one format to another plist_t root_node = NULL; char *plist_out = NULL; int size = 0; - if (memcmp(bplist_entire, "bplist00", 8) == 0) { - bin_to_plist(bplist_entire, filestats->st_size, &root_node); + 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(bplist_entire, filestats->st_size, &root_node); + xml_to_plist(plist_entire, filestats->st_size, &root_node); plist_to_bin(root_node, &plist_out, &size); } - - printf("%s\n", plist_out); + 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; } diff --git a/src/bplist.c b/src/bplist.c index 6136fe9..a5b1c9b 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -567,15 +567,15 @@ void serialize_plist(GNode * node, gpointer data) return; } - +#define Log2(x) (x == 8 ? 3 : (x == 4 ? 2 : (x == 2 ? 1 : 0))) void write_int(GByteArray * bplist, uint64_t val) { uint64_t size = get_needed_bytes(val); uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_UINT | size >> 1; + buff[0] = BPLIST_UINT | Log2(size); memcpy(buff + 1, &val, size); - swap_n_bytes(buff + 1, size); + byte_convert(buff + 1, size); g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); free(buff); } @@ -584,9 +584,9 @@ void write_real(GByteArray * bplist, double val) { uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_REAL | size >> 1; + buff[0] = BPLIST_REAL | Log2(size); memcpy(buff + 1, &val, size); - swap_n_bytes(buff + 1, size); + byte_convert(buff + 1, size); g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); free(buff); } @@ -638,7 +638,7 @@ void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); memcpy(buff + i * dict_param_size, &idx, dict_param_size); - swap_n_bytes(buff + i * dict_param_size, dict_param_size); + byte_convert(buff + i * dict_param_size, dict_param_size); } //now append to bplist @@ -650,7 +650,7 @@ void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) { uint64_t size = g_node_n_children(node) / 2; - uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); + uint8_t marker = BPLIST_DICT | (size < 15 ? size : 0xf); g_byte_array_append(bplist, &marker, sizeof(uint8_t)); if (size >= 15) { GByteArray *int_buff = g_byte_array_new(); @@ -668,22 +668,24 @@ void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8 for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); memcpy(buff + i * dict_param_size, &idx1, dict_param_size); - swap_n_bytes(buff + i * dict_param_size, dict_param_size); + byte_convert(buff + i * dict_param_size, dict_param_size); idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); - swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size); + byte_convert(buff + (i + size) * dict_param_size, dict_param_size); } //now append to bplist - g_byte_array_append(bplist, buff, size * dict_param_size); + g_byte_array_append(bplist, buff, size * 2 * dict_param_size); free(buff); } void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) { - //first serialize tree + //check for valid input + if (!plist || !plist_bin || *plist_bin || !length) + return; //list of objects GPtrArray *objects = g_ptr_array_new(); @@ -692,7 +694,7 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) //serialize plist struct serialize_s ser_s = { objects, ref_table }; - g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s); + serialize_plist(plist, &ser_s); //now stream to output buffer uint8_t offset_size = 0; //unknown yet @@ -759,10 +761,11 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) //write offsets offset_size = get_needed_bytes(bplist_buff->len); + offset_table_index = bplist_buff->len; for (i = 0; i <= num_objects; i++) { uint8_t *buff = (uint8_t *) malloc(offset_size); memcpy(buff, offsets + i, offset_size); - swap_n_bytes(buff, offset_size); + byte_convert(buff, offset_size); g_byte_array_append(bplist_buff, buff, offset_size); free(buff); } diff --git a/src/lockdown.c b/src/lockdown.c index 0957fa2..4c96a7d 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -177,11 +177,8 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) int bytes = 0, i = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; - plist_t plist = NULL; - plist_new_plist(&plist); - - dict_t dict = NULL; - plist_new_dict_in_plist(plist, &dict); + plist_t dict = NULL; + plist_new_dict(&dict); plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType"); @@ -189,23 +186,23 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) char *XML_content = NULL; uint32_t length = 0; - plist_to_xml(plist, &XML_content, &length); + 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); xmlFree(XML_content); XML_content = NULL; - plist_free(plist); - plist = 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, &plist); + xml_to_plist(XML_content, bytes, &dict); - if (!plist) + if (!dict) return IPHONE_E_PLIST_ERROR; - plist_t query_node = find_query_node(plist, "Request", "QueryType"); + 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); @@ -239,19 +236,18 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r { if (!control || !req_key || !value || (value && *value)) return IPHONE_E_INVALID_ARG; - plist_t plist = NULL; - dict_t dict = NULL; + + 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_plist(&plist); - plist_new_dict_in_plist(plist, &dict); + plist_new_dict(&dict); plist_add_dict_element(dict, req_key, PLIST_STRING, (void *) req_string); plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "GetValue"); - plist_to_xml(plist, &XML_content, &length); + plist_to_xml(dict, &XML_content, &length); /* send to iPhone */ log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); @@ -259,8 +255,8 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r xmlFree(XML_content); XML_content = NULL; - plist_free(plist); - plist = NULL; + plist_free(dict); + dict = NULL; if (ret != IPHONE_E_SUCCESS) return ret; @@ -272,11 +268,11 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r if (ret != IPHONE_E_SUCCESS) return ret; - xml_to_plist(XML_content, bytes, &plist); - if (!plist) + xml_to_plist(XML_content, bytes, &dict); + if (!dict) return IPHONE_E_PLIST_ERROR; - plist_t query_node = find_query_node(plist, "Request", "GetValue"); + 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); @@ -314,7 +310,7 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r ret = IPHONE_E_SUCCESS; } - plist_free(plist); + plist_free(dict); free(XML_content); return ret; } @@ -408,9 +404,8 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client 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 plist = NULL; - dict_t dict = NULL; - dict_t dict_record = NULL; + plist_t dict = NULL; + plist_t dict_record = NULL; int bytes = 0, i = 0; char *XML_content = NULL; uint32_t length = 0; @@ -433,8 +428,7 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch } /* Setup Pair request plist */ - plist_new_plist(&plist); - plist_new_dict_in_plist(plist, &dict); + plist_new_dict(&dict); plist_add_dict_element(dict, "PairRecord", PLIST_DICT, NULL); dict_record = g_node_last_child(dict); plist_add_dict_element(dict_record, "DeviceCertificate", PLIST_DATA, (void *) device_cert_b64); @@ -442,15 +436,15 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch plist_add_dict_element(dict_record, "HostID", PLIST_STRING, (void *) host_id); plist_add_dict_element(dict_record, "RootCertificate", PLIST_DATA, (void *) root_cert_b64); plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "Pair"); - plist_to_xml(plist, &XML_content, &length); + 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); xmlFree(XML_content); - plist_free(plist); - plist = NULL; + plist_free(dict); + dict = NULL; if (ret != IPHONE_E_SUCCESS) return ret; @@ -465,11 +459,11 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch log_debug_msg(XML_content); log_debug_msg("\n\n"); - xml_to_plist(XML_content, bytes, &plist); - if (!plist) + xml_to_plist(XML_content, bytes, &dict); + if (!dict) return IPHONE_E_PLIST_ERROR; - plist_t query_node = find_query_node(plist, "Request", "Pair"); + 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); @@ -635,27 +629,25 @@ iphone_error_t lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_ */ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const char *HostID) { - plist_t plist = NULL; - dict_t dict = NULL; + 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_plist(&plist); - plist_new_dict_in_plist(plist, &dict); + plist_new_dict(&dict); plist_add_dict_element(dict, "HostID", PLIST_STRING, (void *) HostID); plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartSession"); - plist_to_xml(plist, &XML_content, &length); + 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); xmlFree(XML_content); XML_content = NULL; - plist_free(plist); - plist = NULL; + plist_free(dict); + dict = NULL; if (ret != IPHONE_E_SUCCESS) return ret; @@ -663,11 +655,11 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c 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, &plist); - if (!plist) + xml_to_plist(XML_content, bytes, &dict); + if (!dict) return IPHONE_E_PLIST_ERROR; - plist_t query_node = find_query_node(plist, "Request", "StartSession"); + 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); @@ -681,8 +673,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c xmlFree(XML_content); XML_content = NULL; - plist_free(plist); - plist = 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")) { @@ -871,8 +863,7 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char return IPHONE_E_SSL_ERROR; - plist_t plist = NULL; - dict_t dict = NULL; + 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; @@ -880,11 +871,10 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char free(host_id); host_id = NULL; - plist_new_plist(&plist); - plist_new_dict_in_plist(plist, &dict); + plist_new_dict(&dict); plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartService"); plist_add_dict_element(dict, "Service", PLIST_STRING, (void *) service); - plist_to_xml(plist, &XML_content, &length); + plist_to_xml(dict, &XML_content, &length); /* send to iPhone */ log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); @@ -892,8 +882,8 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char xmlFree(XML_content); XML_content = NULL; - plist_free(plist); - plist = NULL; + plist_free(dict); + dict = NULL; if (IPHONE_E_SUCCESS != ret) return ret; @@ -903,8 +893,8 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char if (IPHONE_E_SUCCESS != ret) return ret; - xml_to_plist(XML_content, bytes, &plist); - if (!plist) + xml_to_plist(XML_content, bytes, &dict); + if (!dict) return IPHONE_E_PLIST_ERROR; @@ -912,11 +902,11 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char return IPHONE_E_NOT_ENOUGH_DATA; else { - plist_t query_node = find_query_node(plist, "Request", "StartService"); + 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(plist, PLIST_KEY, "Port"); + 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; @@ -947,7 +937,8 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char log_debug_msg("end data received by lockdownd_start_service()\n"); free(XML_content); - plist_free(plist); + plist_free(dict); + dict = NULL; if (port && ret == IPHONE_E_SUCCESS) { *port = port_loc; return IPHONE_E_SUCCESS; diff --git a/src/plist.c b/src/plist.c index 76ae954..66a74c3 100644 --- a/src/plist.c +++ b/src/plist.c @@ -29,7 +29,7 @@ #include -void plist_new_plist(plist_t * plist) +void plist_new_dict(plist_t * plist) { if (*plist != NULL) return; @@ -38,7 +38,16 @@ void plist_new_plist(plist_t * plist) *plist = g_node_new(data); } -void plist_new_dict_in_plist(plist_t plist, dict_t * dict) +void plist_new_array(plist_t * plist) +{ + if (*plist != NULL) + return; + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + data->type = PLIST_ARRAY; + *plist = g_node_new(data); +} + +void plist_new_dict_in_plist(plist_t plist, plist_t * dict) { if (!plist || *dict) return; @@ -49,9 +58,6 @@ void plist_new_dict_in_plist(plist_t plist, dict_t * dict) g_node_append(plist, *dict); } -void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array) -{ -} /** Adds a new key pair to a dict. * @@ -61,7 +67,7 @@ void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void * * @param value a pointer to the actual buffer containing the value. WARNING : the buffer is supposed to match the type of the value * */ -void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value) +void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value) { if (!dict || !key || !value) return; @@ -110,7 +116,7 @@ void plist_free(plist_t plist) g_node_destroy(plist); } -GNode *find_query_node(plist_t plist, char *key, char *request) +plist_t find_query_node(plist_t plist, char *key, char *request) { if (!plist) return NULL; @@ -167,7 +173,7 @@ char compare_node_value(plist_type type, struct plist_data *data, void *value) return res; } -GNode *find_node(plist_t plist, plist_type type, void *value) +plist_t find_node(plist_t plist, plist_type type, void *value) { if (!plist) return NULL; @@ -228,7 +234,10 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) plist_type plist_get_node_type(plist_t node) { - return ((struct plist_data *) node->data)->type; + if (node && node->data) + return ((struct plist_data *) node->data)->type; + else + return PLIST_NONE; } uint64_t plist_get_node_uint_val(plist_t node) diff --git a/src/plist.h b/src/plist.h index e3f3f59..ff4bdbf 100644 --- a/src/plist.h +++ b/src/plist.h @@ -30,8 +30,6 @@ #include #include -char *format_string(const char *buf, int cols, int depth); - typedef enum { PLIST_BOOLEAN, @@ -44,6 +42,7 @@ typedef enum { PLIST_DATE, PLIST_DATA, PLIST_KEY, + PLIST_NONE } plist_type; @@ -63,13 +62,12 @@ struct plist_data { typedef GNode *plist_t; -typedef GNode *dict_t; -typedef GNode *array_t; -void plist_new_plist(plist_t * plist); -void plist_new_dict_in_plist(plist_t plist, dict_t * dict); -void plist_new_array_in_plist(plist_t plist, int length, plist_type type, void **values, array_t * array); -void plist_add_dict_element(dict_t dict, char *key, plist_type type, void *value); + +void plist_new_dict(plist_t * plist); +void plist_new_array(plist_t * plist); +void plist_new_dict_in_plist(plist_t plist, plist_t * dict); +void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value); void plist_free(plist_t plist); void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); @@ -78,8 +76,8 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist); void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); -GNode *find_query_node(plist_t plist, char *key, char *request); -GNode *find_node(plist_t plist, plist_type type, void *value); -void get_type_and_value(GNode * node, plist_type * type, void *value); +plist_t find_query_node(plist_t plist, char *key, char *request); +plist_t find_node(plist_t plist, plist_type type, void *value); +void get_type_and_value(plist_t node, plist_type * type, void *value); #endif diff --git a/src/xplist.c b/src/xplist.c index a87b259..3e975f6 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -89,7 +89,7 @@ struct xml_node { * * @return The plist XML document. */ -xmlDocPtr new_plist() +xmlDocPtr new_xml_plist() { char *plist = strdup(plist_base); xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); @@ -207,7 +207,7 @@ void node_to_xml(GNode * node, gpointer xml_struct) return; } -void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) +void xml_to_node(xmlNodePtr xml_node, plist_t * plist_node) { xmlNodePtr node = NULL; @@ -220,7 +220,10 @@ void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); GNode *subnode = g_node_new(data); - g_node_append(plist_node, subnode); + if (*plist_node) + g_node_append(*plist_node, subnode); + else + *plist_node = subnode; if (!xmlStrcmp(node->name, "true")) { data->boolval = 1; @@ -236,7 +239,7 @@ void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) if (!xmlStrcmp(node->name, "integer")) { char *strval = xmlNodeGetContent(node); - data->intval = atoi(strval); + data->intval = g_ascii_strtoull(strval, NULL, 0); data->type = PLIST_UINT; continue; } @@ -271,13 +274,13 @@ void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) if (!xmlStrcmp(node->name, "array")) { data->type = PLIST_ARRAY; - xml_to_node(node, subnode); + xml_to_node(node, &subnode); continue; } if (!xmlStrcmp(node->name, "dict")) { data->type = PLIST_DICT; - xml_to_node(node, subnode); + xml_to_node(node, &subnode); continue; } } @@ -287,10 +290,12 @@ void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) { if (!plist || !plist_xml || *plist_xml) return; - xmlDocPtr plist_doc = new_plist(); + xmlDocPtr plist_doc = new_xml_plist(); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); struct xml_node root = { root_node, 0 }; - g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); + + node_to_xml(plist, &root); + xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); } @@ -299,8 +304,5 @@ void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - *plist = g_node_new(data); - data->type = PLIST_DICT; - xml_to_node(root_node, *plist); + xml_to_node(root_node, plist); } -- cgit v1.1-32-gdbae From 3d8ba053deeacd74e621469d3d45d1db38ee411a Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 12 Dec 2008 23:39:33 +0100 Subject: Change from Base64 encoded buffers to real buffers. Base64 decoding/encoding only happens in xml plists. --- src/lockdown.c | 143 ++++++++++++++++++++++++++++++++------------------------- src/lockdown.h | 11 +++-- src/plist.c | 8 ++-- src/plist.h | 4 +- src/userpref.c | 10 ++-- src/userpref.h | 2 +- src/xplist.c | 8 +++- 7 files changed, 104 insertions(+), 82 deletions(-) diff --git a/src/lockdown.c b/src/lockdown.c index 4c96a7d..e882128 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -180,7 +180,7 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) plist_t dict = NULL; plist_new_dict(&dict); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType"); + plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType", strlen("QueryType")); log_debug_msg("lockdownd_hello() called\n"); char *XML_content = NULL; @@ -190,7 +190,7 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); ret = iphone_lckd_send(control, XML_content, length, &bytes); - xmlFree(XML_content); + free(XML_content); XML_content = NULL; plist_free(dict); dict = NULL; @@ -211,9 +211,11 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) 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)); - get_type_and_value(value_node, &value_type, (void *) (&value_value)); + 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")) { @@ -232,9 +234,10 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) * * @return IPHONE_E_SUCCESS on success. */ -iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *req_key, char *req_string, char **value) +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 && *value)) + if (!control || !req_key || !value || value->data) return IPHONE_E_INVALID_ARG; plist_t dict = NULL; @@ -245,15 +248,15 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r /* Setup DevicePublicKey request plist */ plist_new_dict(&dict); - plist_add_dict_element(dict, req_key, PLIST_STRING, (void *) req_string); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "GetValue"); + 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); - xmlFree(XML_content); + free(XML_content); XML_content = NULL; plist_free(dict); dict = NULL; @@ -280,9 +283,11 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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)); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + 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")) { @@ -300,13 +305,16 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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)); - get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value)); + 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 = value_value; + value->data = value_value; + value->size = valval_length; ret = IPHONE_E_SUCCESS; } @@ -323,7 +331,9 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r */ iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid) { - return lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", 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. @@ -332,7 +342,7 @@ iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid * * @return 1 on success and 0 on failure. */ -iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, char **public_key) +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); } @@ -410,39 +420,39 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch char *XML_content = NULL; uint32_t length = 0; - char *device_cert_b64 = NULL; - char *host_cert_b64 = NULL; - char *root_cert_b64 = NULL; - char *public_key_b64 = NULL; + 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_b64); + 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_b64, &device_cert_b64, &host_cert_b64, &root_cert_b64); + ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); if (ret != IPHONE_E_SUCCESS) { - free(public_key_b64); + free(public_key.data); return ret; } /* Setup Pair request plist */ plist_new_dict(&dict); - plist_add_dict_element(dict, "PairRecord", PLIST_DICT, NULL); + 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_b64); - plist_add_dict_element(dict_record, "HostCertificate", PLIST_DATA, (void *) host_cert_b64); - plist_add_dict_element(dict_record, "HostID", PLIST_STRING, (void *) host_id); - plist_add_dict_element(dict_record, "RootCertificate", PLIST_DATA, (void *) root_cert_b64); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "Pair"); + 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); - xmlFree(XML_content); + free(XML_content); plist_free(dict); dict = NULL; @@ -471,9 +481,11 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch 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)); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + 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")) { @@ -483,13 +495,13 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch /* 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_b64); + 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_b64); + free(public_key.data); return ret; } @@ -498,25 +510,19 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch * * @return IPHONE_E_SUCCESS on success. */ -iphone_error_t lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_b64, char **host_cert_b64, - char **root_cert_b64) +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_b64 || !device_cert_b64 || !host_cert_b64 || !root_cert_b64) + 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 }; - /* first decode base64 public_key */ - gnutls_datum_t pem_pub_key; - gsize decoded_size; - pem_pub_key.data = g_base64_decode(public_key_b64, &decoded_size); - pem_pub_key.size = decoded_size; - /* now decode the PEM encoded key */ gnutls_datum_t der_pub_key; - if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &pem_pub_key, &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; @@ -600,10 +606,18 @@ iphone_error_t lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_ dev_pem.data = gnutls_malloc(dev_pem.size); gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size); - /* now encode certificates for output */ - *device_cert_b64 = g_base64_encode(dev_pem.data, dev_pem.size); - *host_cert_b64 = g_base64_encode(pem_host_cert.data, pem_host_cert.size); - *root_cert_b64 = g_base64_encode(pem_root_cert.data, pem_root_cert.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); @@ -615,7 +629,6 @@ iphone_error_t lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_ gnutls_free(exponent.data); gnutls_free(der_pub_key.data); - g_free(pem_pub_key.data); return ret; } @@ -637,14 +650,14 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c /* Setup DevicePublicKey request plist */ plist_new_dict(&dict); - plist_add_dict_element(dict, "HostID", PLIST_STRING, (void *) HostID); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartSession"); + 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); - xmlFree(XML_content); + free(XML_content); XML_content = NULL; plist_free(dict); dict = NULL; @@ -667,11 +680,13 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c 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)); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); + 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); - xmlFree(XML_content); + free(XML_content); XML_content = NULL; plist_free(dict); dict = NULL; @@ -872,15 +887,15 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char host_id = NULL; plist_new_dict(&dict); - plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartService"); - plist_add_dict_element(dict, "Service", PLIST_STRING, (void *) service); + 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); - xmlFree(XML_content); + free(XML_content); XML_content = NULL; plist_free(dict); dict = NULL; @@ -916,12 +931,16 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char 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)); - get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value)); - get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key)); - get_type_and_value(port_value_node, &port_value_type, (void *) (&port_value)); + 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 && diff --git a/src/lockdown.h b/src/lockdown.h index b75d4bf..8b3dd41 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -42,13 +42,14 @@ struct iphone_lckd_client_int { 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, char **value); +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, char **public_key); +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(char *public_key_b64, char **device_cert_b64, char **host_cert_b64, - char **root_cert_b64); -iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *public_key, char *host_id); +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 diff --git a/src/plist.c b/src/plist.c index 66a74c3..932ea5e 100644 --- a/src/plist.c +++ b/src/plist.c @@ -67,7 +67,7 @@ void plist_new_dict_in_plist(plist_t plist, plist_t * dict) * @param value a pointer to the actual buffer containing the value. WARNING : the buffer is supposed to match the type of the value * */ -void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value) +void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value, uint64_t length) { if (!dict || !key || !value) return; @@ -81,6 +81,7 @@ void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *valu //now handle value struct plist_data *val = (struct plist_data *) calloc(sizeof(struct plist_data), 1); val->type = type; + val->length = length; switch (type) { case PLIST_BOOLEAN: @@ -99,7 +100,7 @@ void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *valu val->unicodeval = wcsdup((wchar_t *) value); break; case PLIST_DATA: - val->buff = strdup((char *) value); + memcpy(val->buff, value, length); break; case PLIST_ARRAY: case PLIST_DICT: @@ -195,7 +196,7 @@ plist_t find_node(plist_t plist, plist_type type, void *value) return NULL; } -void get_type_and_value(GNode * node, plist_type * type, void *value) +void get_type_and_value(GNode * node, plist_type * type, void *value, uint64_t * length) { if (!node) return; @@ -203,6 +204,7 @@ void get_type_and_value(GNode * node, plist_type * type, void *value) struct plist_data *data = (struct plist_data *) node->data; *type = data->type; + *length = data->length; switch (*type) { case PLIST_BOOLEAN: diff --git a/src/plist.h b/src/plist.h index ff4bdbf..1dc464a 100644 --- a/src/plist.h +++ b/src/plist.h @@ -67,7 +67,7 @@ typedef GNode *plist_t; void plist_new_dict(plist_t * plist); void plist_new_array(plist_t * plist); void plist_new_dict_in_plist(plist_t plist, plist_t * dict); -void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value); +void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value, uint64_t length); void plist_free(plist_t plist); void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); @@ -78,6 +78,6 @@ void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); plist_t find_query_node(plist_t plist, char *key, char *request); plist_t find_node(plist_t plist, plist_type type, void *value); -void get_type_and_value(plist_t node, plist_type * type, void *value); +void get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length); #endif diff --git a/src/userpref.c b/src/userpref.c index db54679..b707957 100644 --- a/src/userpref.c +++ b/src/userpref.c @@ -114,10 +114,10 @@ int is_device_known(char *uid) * @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, char *public_key) +int store_device_public_key(char *uid, gnutls_datum_t public_key) { - if (NULL == public_key || is_device_known(uid)) + if (NULL == public_key.data || is_device_known(uid)) return 0; /* ensure config directory exists */ @@ -127,15 +127,11 @@ int store_device_public_key(char *uid, char *public_key) 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); - /* decode public key for storing */ - gsize decoded_size; - gchar *data = g_base64_decode(public_key, &decoded_size); /* store file */ FILE *pFile = fopen(pem, "wb"); - fwrite(data, 1, decoded_size, pFile); + fwrite(public_key.data, 1, public_key.size, pFile); fclose(pFile); g_free(pem); - g_free(data); g_free(device_file); return 1; } diff --git a/src/userpref.h b/src/userpref.h index 5171929..450549f 100644 --- a/src/userpref.h +++ b/src/userpref.h @@ -40,7 +40,7 @@ int is_device_known(char *uid); /** * @return 1 if everything went well. Returns 0 otherwise. */ -int store_device_public_key(char *uid, char *public_key); +int store_device_public_key(char *uid, gnutls_datum_t public_key); /** * @return 1 if everything went well. Returns 0 otherwise. diff --git a/src/xplist.c b/src/xplist.c index 3e975f6..2d650b4 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -165,7 +165,9 @@ void node_to_xml(GNode * node, gpointer xml_struct) case PLIST_DATA: tag = "data"; - val = format_string(node_data->buff, 60, xstruct->depth); + gchar *valtmp = g_base64_encode(node_data->buff, node_data->length); + val = format_string(valtmp, 60, xstruct->depth); + g_free(valtmp); break; case PLIST_ARRAY: tag = "array"; @@ -267,7 +269,9 @@ void xml_to_node(xmlNodePtr xml_node, plist_t * plist_node) } if (!xmlStrcmp(node->name, "data")) { - data->buff = strdup(xmlNodeGetContent(node)); + gsize size = 0; + data->buff = g_base64_decode(xmlNodeGetContent(node), &size); + data->length = size; data->type = PLIST_DATA; continue; } -- cgit v1.1-32-gdbae From 4301ef9bb8e9d06ffa4e9172191d58ede5e16f5d Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sat, 13 Dec 2008 18:12:46 +0100 Subject: fork out plist stuff in libplist and migrate libiphone to use it. --- configure.ac | 1 + dev/Makefile.am | 6 +- dev/plutil.c | 118 --------- dev/plutil.h | 13 - src/AFC.c | 1 - src/Makefile.am | 6 +- src/bplist.c | 793 -------------------------------------------------------- src/lockdown.c | 130 +++++----- src/lockdown.h | 1 - src/plist.c | 251 ------------------ src/plist.h | 83 ------ src/xplist.c | 312 ---------------------- 12 files changed, 76 insertions(+), 1639 deletions(-) delete mode 100644 dev/plutil.c delete mode 100644 dev/plutil.h delete mode 100644 src/bplist.c delete mode 100644 src/plist.c delete mode 100644 src/plist.h delete mode 100644 src/xplist.c diff --git a/configure.ac b/configure.ac index 286b1d8..9516ec4 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,7 @@ 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) +PKG_CHECK_MODULES(libplist, libplist-1.0 >= 0.1.0) # Checks for header files. AC_HEADER_STDC diff --git a/dev/Makefile.am b/dev/Makefile.am index 95b4d61..d116581 100644 --- a/dev/Makefile.am +++ b/dev/Makefile.am @@ -3,7 +3,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) -bin_PROGRAMS = iphoneclient lckd-client afccheck plutil +bin_PROGRAMS = iphoneclient lckd-client afccheck iphoneclient_SOURCES = main.c iphoneclient_LDADD = ../src/libiphone.la @@ -18,7 +18,3 @@ 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/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/src/AFC.c b/src/AFC.c index 899bd47..aefb971 100644 --- a/src/AFC.c +++ b/src/AFC.c @@ -21,7 +21,6 @@ #include #include "AFC.h" -#include "plist.h" // This is the maximum size an AFC data packet can be diff --git a/src/Makefile.am b/src/Makefile.am index 82fd924..2514367 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +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) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) -g +AM_LDFLAGS = $(libxml2_LIBS) $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_LIBS) bin_PROGRAMS = libiphone-initconf @@ -12,4 +12,4 @@ 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 +libiphone_la_SOURCES = usbmux.c iphone.c lockdown.c AFC.c userpref.c utils.c diff --git a/src/bplist.c b/src/bplist.c deleted file mode 100644 index a5b1c9b..0000000 --- a/src/bplist.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * plist.c - * Binary plist implementation - * - * 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 "plist.h" -#include -#include -#include -#include - -/* Magic marker and size. */ -#define BPLIST_MAGIC "bplist" -#define BPLIST_MAGIC_SIZE 6 - -#define BPLIST_VERSION "00" -#define BPLIST_VERSION_SIZE 2 - - -#define BPLIST_TRL_SIZE 26 -#define BPLIST_TRL_OFFSIZE_IDX 0 -#define BPLIST_TRL_PARMSIZE_IDX 1 -#define BPLIST_TRL_NUMOBJ_IDX 2 -#define BPLIST_TRL_ROOTOBJ_IDX 10 -#define BPLIST_TRL_OFFTAB_IDX 18 - -enum { - BPLIST_NULL = 0x00, - BPLIST_TRUE = 0x08, - BPLIST_FALSE = 0x09, - BPLIST_FILL = 0x0F, /* will be used for length grabbing */ - BPLIST_UINT = 0x10, - BPLIST_REAL = 0x20, - BPLIST_DATE = 0x30, - BPLIST_DATA = 0x40, - BPLIST_STRING = 0x50, - BPLIST_UNICODE = 0x60, - BPLIST_UID = 0x70, - BPLIST_ARRAY = 0xA0, - BPLIST_SET = 0xC0, - BPLIST_DICT = 0xD0, - BPLIST_MASK = 0xF0 -}; - -void byte_convert(char *address, size_t size) -{ - int i = 0, j = 0; - char tmp = '\0'; - - for (i = 0; i < (size / 2); i++) { - tmp = address[i]; - j = ((size - 1) + 0) - i; - address[i] = address[j]; - address[j] = tmp; - } -} - -#include -#define swap_n_bytes(x, n) \ - n == 8 ? bswap_64(*(uint64_t *)(x)) : \ - (n == 4 ? bswap_32(*(uint32_t *)(x)) : \ - (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) )) - -#define be64dec(x) bswap_64( *(uint64_t*)(x) ) - -#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8))) -#define get_real_bytes(x) (x >> 32 ? 4 : 8) - -GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - size = 1 << size; // make length less misleading - switch (size) { - case sizeof(uint8_t): - data->intval = bnode[0]; - break; - case sizeof(uint16_t): - memcpy(&data->intval, bnode, size); - data->intval = ntohs(data->intval); - break; - case sizeof(uint32_t): - memcpy(&data->intval, bnode, size); - data->intval = ntohl(data->intval); - break; - case sizeof(uint64_t): - memcpy(&data->intval, bnode, size); - byte_convert((char *) &data->intval, size); - break; - default: - free(data); - return NULL; - }; - - *next_object = bnode + size; - data->type = PLIST_UINT; - return g_node_new(data); -} - -GNode *parse_real_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - size = 1 << size; // make length less misleading - switch (size) { - case sizeof(float): - memcpy(&data->realval, bnode, size); - byte_convert((char *) &data->realval, size); - break; - case sizeof(double): - memcpy(&data->realval, bnode, size); - byte_convert((char *) &data->realval, size); - break; - default: - free(data); - return NULL; - } - data->type = PLIST_REAL; - return g_node_new(data); -} - -GNode *parse_string_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_STRING; - data->strval = (char *) malloc(sizeof(char) * (size + 1)); - memcpy(data->strval, bnode, size); - data->strval[size] = '\0'; - - return g_node_new(data); -} - -GNode *parse_unicode_node(char *bnode, uint8_t size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_UNICODE; - data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1)); - memcpy(data->unicodeval, bnode, size); - data->unicodeval[size] = '\0'; - - return g_node_new(data); -} - -GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_DATA; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size); - memcpy(data->buff, bnode, sizeof(char) * size); - - return g_node_new(data); -} - -GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_DICT; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2); - memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2); - - return g_node_new(data); -} - -GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) -{ - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - data->type = PLIST_ARRAY; - data->length = size; - data->buff = (char *) malloc(sizeof(char) * size * ref_size); - memcpy(data->buff, bnode, sizeof(char) * size * ref_size); - - return g_node_new(data); -} - - - -GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object) -{ - if (!object) - return NULL; - - uint16_t type = *object & 0xF0; - uint64_t size = *object & 0x0F; - object++; - - switch (type) { - - case BPLIST_NULL: - switch (size) { - - case BPLIST_TRUE: - { - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_BOOLEAN; - data->boolval = TRUE; - return g_node_new(data); - } - - case BPLIST_FALSE: - { - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_BOOLEAN; - data->boolval = FALSE; - return g_node_new(data); - } - - case BPLIST_NULL: - default: - return NULL; - } - - case BPLIST_UINT: - return parse_uint_node(object, size, next_object); - - case BPLIST_REAL: - return parse_real_node(object, size); - - case BPLIST_DATE: - if (3 != size) - return NULL; - else - return parse_real_node(object, size); - - case BPLIST_DATA: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_data_node(object, size, dict_size); - - case BPLIST_STRING: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_string_node(object, size); - - case BPLIST_UNICODE: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_unicode_node(object, size); - - case BPLIST_UID: - case BPLIST_ARRAY: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - size = plist_get_node_uint_val(size_node); - } - return parse_array_node(object, size, dict_size); - - case BPLIST_SET: - case BPLIST_DICT: - if (0x0F == size) { - plist_t size_node = parse_bin_node(object, dict_size, &object); - if (plist_get_node_type(size_node) != PLIST_UINT) - return NULL; - object++; - size = plist_get_node_uint_val(size_node); - } - return parse_dict_node(object, size, dict_size); - - } - return NULL; -} - -gpointer copy_plist_data(gconstpointer src, gpointer data) -{ - struct plist_data *srcdata = (struct plist_data *) src; - struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - - dstdata->type = srcdata->type; - dstdata->length = srcdata->length; - switch (dstdata->type) { - case PLIST_BOOLEAN: - dstdata->boolval = srcdata->boolval; - break; - case PLIST_UINT: - dstdata->intval = srcdata->intval; - break; - case PLIST_DATE: - case PLIST_REAL: - dstdata->realval = srcdata->realval; - break; - case PLIST_KEY: - case PLIST_STRING: - dstdata->strval = strdup(srcdata->strval); - break; - case PLIST_UNICODE: - dstdata->unicodeval = wcsdup(srcdata->unicodeval); - break; - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length); - memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length); - break; - - default: - break; - } - - return dstdata; -} - -void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist) -{ - //first check we have enough data - if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) - return; - //check that plist_bin in actually a plist - if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) - return; - //check for known version - if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) - return; - - //now parse trailer - const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); - - uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; - uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; - uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); - uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); - uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); - - log_debug_msg("Offset size: %i\n", offset_size); - log_debug_msg("Ref size: %i\n", dict_param_size); - log_debug_msg("Number of objects: %lli\n", num_objects); - log_debug_msg("Root object index: %lli\n", root_object); - log_debug_msg("Offset table index: %lli\n", offset_table_index); - - if (num_objects == 0) - return; - - //allocate serialized array of nodes - plist_t *nodeslist = NULL; - nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); - - if (!nodeslist) - return; - - //parse serialized nodes - uint64_t i = 0; - uint64_t current_offset = 0; - const char *offset_table = plist_bin + offset_table_index; - for (i = 0; i < num_objects; i++) { - current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size); - - log_debug_msg("parse_nodes: current_offset = %i\n", current_offset); - char *obj = plist_bin + current_offset; - nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); - log_debug_msg("parse_nodes: parse_raw_node done\n"); - } - - //setup children for structured types - int j = 0, str_i = 0, str_j = 0; - uint32_t index1 = 0, index2 = 0; - - for (i = 0; i < num_objects; i++) { - - log_debug_msg("parse_nodes: on node %i\n", i); - struct plist_data *data = (struct plist_data *) nodeslist[i]->data; - - switch (data->type) { - case PLIST_DICT: - log_debug_msg("parse_nodes: dictionary found\n"); - for (j = 0; j < data->length; j++) { - str_i = j * dict_param_size; - str_j = (j + data->length) * dict_param_size; - - index1 = swap_n_bytes(data->buff + str_i, dict_param_size); - index2 = swap_n_bytes(data->buff + str_j, dict_param_size); - - //first one is actually a key - ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY; - - if (G_NODE_IS_ROOT(nodeslist[index1])) - g_node_append(nodeslist[i], nodeslist[index1]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); - - if (G_NODE_IS_ROOT(nodeslist[index2])) - g_node_append(nodeslist[i], nodeslist[index2]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL)); - } - - free(data->buff); - break; - - case PLIST_ARRAY: - log_debug_msg("parse_nodes: array found\n"); - for (j = 0; j < data->length; j++) { - str_j = j * dict_param_size; - index1 = swap_n_bytes(data->buff + str_j, dict_param_size); - - //g_node_append(nodeslist[i], nodeslist[index1]); - if (G_NODE_IS_ROOT(nodeslist[index1])) - g_node_append(nodeslist[i], nodeslist[index1]); - else - g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL)); - } - free(data->buff); - break; - default: - break; - } - } - - *plist = nodeslist[root_object]; -} - -guint plist_data_hash(gconstpointer key) -{ - struct plist_data *data = (struct plist_data *) ((GNode *) key)->data; - - guint hash = data->type; - guint i = 0; - - char *buff = NULL; - guint size = 0; - - switch (data->type) { - case PLIST_BOOLEAN: - case PLIST_UINT: - case PLIST_REAL: - buff = (char *) &data->intval; - size = 8; - break; - case PLIST_KEY: - case PLIST_STRING: - buff = data->strval; - size = strlen(buff); - break; - case PLIST_UNICODE: - buff = data->unicodeval; - size = strlen(buff) * sizeof(wchar_t); - break; - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - //for these types only hash pointer - buff = &key; - size = sizeof(gconstpointer); - break; - case PLIST_DATE: - default: - break; - } - - //now perform hash - for (i = 0; i < size; buff++, i++) - hash = hash << 7 ^ (*buff); - - return hash; -} - -gboolean plist_data_compare(gconstpointer a, gconstpointer b) -{ - if (!a || !b) - return FALSE; - - if (!((GNode *) a)->data || !((GNode *) b)->data) - return FALSE; - - struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data; - struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data; - - if (val_a->type != val_b->type) - return FALSE; - - switch (val_a->type) { - case PLIST_BOOLEAN: - case PLIST_UINT: - case PLIST_REAL: - if (val_a->intval == val_b->intval) //it is an union so this is sufficient - return TRUE; - else - return FALSE; - - case PLIST_KEY: - case PLIST_STRING: - if (!strcmp(val_a->strval, val_b->strval)) - return TRUE; - else - return FALSE; - case PLIST_UNICODE: - if (!strcmp(val_a->unicodeval, val_b->unicodeval)) - return TRUE; - else - return FALSE; - - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - //compare pointer - if (a == b) - return TRUE; - else - return FALSE; - break; - case PLIST_DATE: - default: - break; - } - return FALSE; -} - -struct serialize_s { - GPtrArray *objects; - GHashTable *ref_table; -}; - -void serialize_plist(GNode * node, gpointer data) -{ - struct serialize_s *ser = (struct serialize_s *) data; - uint64_t current_index = ser->objects->len; - - //first check that node is not yet in objects - gpointer val = g_hash_table_lookup(ser->ref_table, node); - if (val) { - //data is already in table - return; - } - //insert new ref - g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index)); - - //now append current node to object array - g_ptr_array_add(ser->objects, node); - - //now recurse on children - g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data); - return; -} - -#define Log2(x) (x == 8 ? 3 : (x == 4 ? 2 : (x == 2 ? 1 : 0))) - -void write_int(GByteArray * bplist, uint64_t val) -{ - uint64_t size = get_needed_bytes(val); - uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_UINT | Log2(size); - memcpy(buff + 1, &val, size); - byte_convert(buff + 1, size); - g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); - free(buff); -} - -void write_real(GByteArray * bplist, double val) -{ - uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space - uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size); - buff[0] = BPLIST_REAL | Log2(size); - memcpy(buff + 1, &val, size); - byte_convert(buff + 1, size); - g_byte_array_append(bplist, buff, sizeof(uint8_t) + size); - free(buff); -} - -void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) -{ - uint8_t marker = mark | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - uint8_t *buff = (uint8_t *) malloc(size); - memcpy(buff, val, size); - g_byte_array_append(bplist, buff, size); - free(buff); -} - -void write_data(GByteArray * bplist, uint8_t * val, uint64_t size) -{ - write_raw_data(bplist, BPLIST_DATA, val, size); -} - -void write_string(GByteArray * bplist, char *val) -{ - uint64_t size = strlen(val); - write_raw_data(bplist, BPLIST_STRING, val, size); -} - -void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) -{ - uint64_t size = g_node_n_children(node); - uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - - uint64_t idx = 0; - uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); - - GNode *cur = NULL; - int i = 0; - for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { - idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); - memcpy(buff + i * dict_param_size, &idx, dict_param_size); - byte_convert(buff + i * dict_param_size, dict_param_size); - } - - //now append to bplist - g_byte_array_append(bplist, buff, size * dict_param_size); - free(buff); - -} - -void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) -{ - uint64_t size = g_node_n_children(node) / 2; - uint8_t marker = BPLIST_DICT | (size < 15 ? size : 0xf); - g_byte_array_append(bplist, &marker, sizeof(uint8_t)); - if (size >= 15) { - GByteArray *int_buff = g_byte_array_new(); - write_int(int_buff, size); - g_byte_array_append(bplist, int_buff->data, int_buff->len); - g_byte_array_free(int_buff, TRUE); - } - - uint64_t idx1 = 0; - uint64_t idx2 = 0; - uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); - - GNode *cur = NULL; - int i = 0; - for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { - idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); - memcpy(buff + i * dict_param_size, &idx1, dict_param_size); - byte_convert(buff + i * dict_param_size, dict_param_size); - - idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next)); - memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size); - byte_convert(buff + (i + size) * dict_param_size, dict_param_size); - } - - //now append to bplist - g_byte_array_append(bplist, buff, size * 2 * dict_param_size); - free(buff); - -} - -void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) -{ - //check for valid input - if (!plist || !plist_bin || *plist_bin || !length) - return; - - //list of objects - GPtrArray *objects = g_ptr_array_new(); - //hashtable to write only once same nodes - GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); - - //serialize plist - struct serialize_s ser_s = { objects, ref_table }; - serialize_plist(plist, &ser_s); - - //now stream to output buffer - uint8_t offset_size = 0; //unknown yet - uint8_t dict_param_size = get_needed_bytes(objects->len); - uint64_t num_objects = objects->len; - uint64_t root_object = 0; //root is first in list - uint64_t offset_table_index = 0; //unknown yet - - //setup a dynamic bytes array to store bplist in - GByteArray *bplist_buff = g_byte_array_new(); - - //set magic number and version - g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); - g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); - - //write objects and table - int i = 0; - uint8_t *buff = NULL; - uint8_t size = 0; - uint64_t offsets[num_objects]; - for (i = 0; i < num_objects; i++) { - - offsets[i] = bplist_buff->len; - struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data; - - switch (data->type) { - case PLIST_BOOLEAN: - buff = (uint8_t *) malloc(sizeof(uint8_t)); - buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE; - g_byte_array_append(bplist_buff, buff, sizeof(uint8_t)); - free(buff); - break; - - case PLIST_UINT: - write_int(bplist_buff, data->intval); - break; - - case PLIST_REAL: - write_real(bplist_buff, data->realval); - break; - - case PLIST_KEY: - case PLIST_STRING: - write_string(bplist_buff, data->strval); - break; - case PLIST_UNICODE: - //TODO - break; - case PLIST_DATA: - write_data(bplist_buff, data->strval, data->length); - case PLIST_ARRAY: - write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); - break; - case PLIST_DICT: - write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size); - break; - case PLIST_DATE: - //TODO - break; - default: - break; - } - } - - //write offsets - offset_size = get_needed_bytes(bplist_buff->len); - offset_table_index = bplist_buff->len; - for (i = 0; i <= num_objects; i++) { - uint8_t *buff = (uint8_t *) malloc(offset_size); - memcpy(buff, offsets + i, offset_size); - byte_convert(buff, offset_size); - g_byte_array_append(bplist_buff, buff, offset_size); - free(buff); - } - - //setup trailer - num_objects = bswap_64(num_objects); - root_object = bswap_64(root_object); - offset_table_index = bswap_64(offset_table_index); - - char trailer[BPLIST_TRL_SIZE]; - memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); - memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); - memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); - memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t)); - memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t)); - - g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE); - - //duplicate buffer - *plist_bin = (char *) malloc(bplist_buff->len); - memcpy(*plist_bin, bplist_buff->data, bplist_buff->len); - *length = bplist_buff->len; - - g_byte_array_free(bplist_buff, TRUE); -} diff --git a/src/lockdown.c b/src/lockdown.c index e882128..5b83fb9 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -30,6 +30,8 @@ #include #include +#include + const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { {"PKCS1", 536872976, 0}, {0, 1073741836, 0}, @@ -177,10 +179,9 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) 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")); + plist_t dict = plist_new_dict(); + plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); + plist_add_sub_element(dict, PLIST_STRING, (void *) "QueryType", strlen("QueryType")); log_debug_msg("lockdownd_hello() called\n"); char *XML_content = NULL; @@ -197,14 +198,14 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) 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); + plist_from_xml(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_t query_node = plist_find_node(dict, PLIST_STRING, "QueryType", strlen("QueryType")); + plist_t result_node = plist_get_next_sibling(query_node); + plist_t value_node = plist_get_next_sibling(result_node); plist_type result_type; plist_type value_type; @@ -214,8 +215,8 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) 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); + plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length); + plist_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")) { @@ -247,9 +248,11 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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")); + dict = plist_new_dict(); + plist_add_sub_element(dict, PLIST_KEY, (void *) req_key, strlen(req_key)); + plist_add_sub_element(dict, PLIST_STRING, (void *) req_string, strlen(req_string)); + plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); + plist_add_sub_element(dict, PLIST_STRING, (void *) "GetValue", strlen("GetValue")); plist_to_xml(dict, &XML_content, &length); /* send to iPhone */ @@ -271,13 +274,13 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r if (ret != IPHONE_E_SUCCESS) return ret; - xml_to_plist(XML_content, bytes, &dict); + plist_from_xml(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_t query_node = plist_find_node(dict, PLIST_STRING, "GetValue", strlen("GetValue")); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_next_sibling(result_key_node); plist_type result_key_type; plist_type result_value_type; @@ -286,8 +289,8 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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); + plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &result_length); + plist_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")) { @@ -299,8 +302,8 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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_t value_key_node = plist_get_next_sibling(result_key_node); + plist_t value_value_node = plist_get_next_sibling(value_key_node); plist_type value_key_type; plist_type value_value_type; char *value_key = NULL; @@ -308,8 +311,8 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *r 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); + plist_get_type_and_value(value_key_node, &value_key_type, (void *) (&value_key), &key_length); + plist_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"); @@ -438,14 +441,19 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch } /* 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")); + dict = plist_new_dict(); + plist_add_sub_element(dict, PLIST_KEY, (void *) "PairRecord", strlen("PairRecord")); + dict_record = plist_add_sub_element(dict, PLIST_DICT, NULL, 0); + plist_add_sub_element(dict_record, PLIST_KEY, (void *) "DeviceCertificate", strlen("DeviceCertificate")); + plist_add_sub_element(dict_record, PLIST_DATA, (void *) device_cert.data, device_cert.size); + plist_add_sub_element(dict_record, PLIST_KEY, (void *) "HostCertificate", strlen("HostCertificate")); + plist_add_sub_element(dict_record, PLIST_DATA, (void *) host_cert.data, host_cert.size); + plist_add_sub_element(dict_record, PLIST_KEY, (void *) "HostID", strlen("HostID")); + plist_add_sub_element(dict_record, PLIST_STRING, (void *) host_id, strlen(host_id)); + plist_add_sub_element(dict_record, PLIST_KEY, (void *) "RootCertificate", strlen("RootCertificate")); + plist_add_sub_element(dict_record, PLIST_DATA, (void *) root_cert.data, root_cert.size); + plist_add_sub_element(dict_record, PLIST_KEY, (void *) "Request", strlen("Request")); + plist_add_sub_element(dict_record, 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); @@ -469,13 +477,13 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch log_debug_msg(XML_content); log_debug_msg("\n\n"); - xml_to_plist(XML_content, bytes, &dict); + plist_from_xml(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_t query_node = plist_find_node(dict, PLIST_STRING, "Pair", strlen("Pair")); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_next_sibling(result_key_node); plist_type result_key_type; plist_type result_value_type; @@ -484,8 +492,8 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch 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); + plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); + plist_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")) { @@ -649,9 +657,11 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c 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")); + dict = plist_new_dict(); + plist_add_sub_element(dict, PLIST_KEY, (void *) "HostID", strlen("HostID")); + plist_add_sub_element(dict, PLIST_STRING, (void *) HostID, strlen(HostID)); + plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); + plist_add_sub_element(dict, 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); @@ -668,13 +678,13 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c 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); + plist_from_xml(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_t query_node = plist_find_node(dict, PLIST_STRING, "StartSession", strlen("StartSession")); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_next_sibling(result_key_node); plist_type result_key_type; plist_type result_value_type; @@ -683,8 +693,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c 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); + plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); + plist_get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length); free(XML_content); XML_content = NULL; @@ -886,9 +896,11 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char 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)); + dict = plist_new_dict(); + plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); + plist_add_sub_element(dict, PLIST_STRING, (void *) "StartService", strlen("StartService")); + plist_add_sub_element(dict, PLIST_KEY, (void *) "Service", strlen("Service")); + plist_add_sub_element(dict, PLIST_STRING, (void *) service, strlen(service)); plist_to_xml(dict, &XML_content, &length); /* send to iPhone */ @@ -908,7 +920,7 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char if (IPHONE_E_SUCCESS != ret) return ret; - xml_to_plist(XML_content, bytes, &dict); + plist_from_xml(XML_content, bytes, &dict); if (!dict) return IPHONE_E_PLIST_ERROR; @@ -917,12 +929,12 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char 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 query_node = plist_find_node(dict, PLIST_STRING, "StartService", strlen("StartService")); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_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_t port_key_node = plist_find_node(dict, PLIST_KEY, "Port", strlen("Port")); + plist_t port_value_node = plist_get_next_sibling(port_key_node); plist_type result_key_type; plist_type result_value_type; @@ -937,10 +949,10 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char 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); + plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &res_key_length); + plist_get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &res_val_length); + plist_get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key), &port_key_length); + plist_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 && diff --git a/src/lockdown.h b/src/lockdown.h index 8b3dd41..18e13aa 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -23,7 +23,6 @@ #define LOCKDOWND_H #include "usbmux.h" -#include "plist.h" #include #include diff --git a/src/plist.c b/src/plist.c deleted file mode 100644 index 932ea5e..0000000 --- a/src/plist.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * plist.c - * Builds plist XML 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 -#include -#include "utils.h" -#include "plist.h" -#include -#include -#include - - -void plist_new_dict(plist_t * plist) -{ - if (*plist != NULL) - return; - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_DICT; - *plist = g_node_new(data); -} - -void plist_new_array(plist_t * plist) -{ - if (*plist != NULL) - return; - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_ARRAY; - *plist = g_node_new(data); -} - -void plist_new_dict_in_plist(plist_t plist, plist_t * dict) -{ - if (!plist || *dict) - return; - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_DICT; - *dict = g_node_new(data); - g_node_append(plist, *dict); -} - - -/** Adds a new key pair to a dict. - * - * @param dict The dict node in the plist. - * @param key the key name of the key pair. - * @param type The the type of the value in the key pair. - * @param value a pointer to the actual buffer containing the value. WARNING : the buffer is supposed to match the type of the value - * - */ -void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value, uint64_t length) -{ - if (!dict || !key || !value) - return; - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - data->type = PLIST_KEY; - data->strval = strdup(key); - GNode *keynode = g_node_new(data); - g_node_append(dict, keynode); - - //now handle value - struct plist_data *val = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - val->type = type; - val->length = length; - - switch (type) { - case PLIST_BOOLEAN: - val->boolval = *((char *) value); - break; - case PLIST_UINT: - val->intval = *((uint64_t *) value); - break; - case PLIST_REAL: - val->realval = *((double *) value); - break; - case PLIST_STRING: - val->strval = strdup((char *) value); - break; - case PLIST_UNICODE: - val->unicodeval = wcsdup((wchar_t *) value); - break; - case PLIST_DATA: - memcpy(val->buff, value, length); - break; - case PLIST_ARRAY: - case PLIST_DICT: - case PLIST_DATE: - default: - break; - } - GNode *valnode = g_node_new(val); - g_node_append(dict, valnode); -} - -void plist_free(plist_t plist) -{ - g_node_destroy(plist); -} - -plist_t find_query_node(plist_t plist, char *key, char *request) -{ - if (!plist) - return NULL; - - GNode *current = NULL; - for (current = plist->children; current; current = current->next) { - - struct plist_data *data = (struct plist_data *) current->data; - - if (data->type == PLIST_KEY && !strcmp(data->strval, key) && current->next) { - - data = (struct plist_data *) current->next->data; - if (data->type == PLIST_STRING && !strcmp(data->strval, request)) - return current->next; - } - if (data->type == PLIST_DICT || data->type == PLIST_ARRAY) { - GNode *sub = find_query_node(current, key, request); - if (sub) - return sub; - } - } - return NULL; -} - -char compare_node_value(plist_type type, struct plist_data *data, void *value) -{ - char res = FALSE; - switch (type) { - case PLIST_BOOLEAN: - res = data->boolval == *((char *) value) ? TRUE : FALSE; - break; - case PLIST_UINT: - res = data->intval == *((uint64_t *) value) ? TRUE : FALSE; - break; - case PLIST_REAL: - res = data->realval == *((double *) value) ? TRUE : FALSE; - break; - case PLIST_KEY: - case PLIST_STRING: - res = !strcmp(data->strval, ((char *) value)); - break; - case PLIST_UNICODE: - res = !wcscmp(data->unicodeval, ((wchar_t *) value)); - break; - case PLIST_DATA: - res = !strcmp(data->buff, ((char *) value)); - break; - case PLIST_ARRAY: - case PLIST_DICT: - case PLIST_DATE: - default: - break; - } - return res; -} - -plist_t find_node(plist_t plist, plist_type type, void *value) -{ - if (!plist) - return NULL; - - GNode *current = NULL; - for (current = plist->children; current; current = current->next) { - - struct plist_data *data = (struct plist_data *) current->data; - - if (data->type == type && compare_node_value(type, data, value)) { - return current; - } - if (data->type == PLIST_DICT || data->type == PLIST_ARRAY) { - GNode *sub = find_node(current, type, value); - if (sub) - return sub; - } - } - return NULL; -} - -void get_type_and_value(GNode * node, plist_type * type, void *value, uint64_t * length) -{ - if (!node) - return; - - struct plist_data *data = (struct plist_data *) node->data; - - *type = data->type; - *length = data->length; - - switch (*type) { - case PLIST_BOOLEAN: - *((char *) value) = data->boolval; - break; - case PLIST_UINT: - *((uint64_t *) value) = data->intval; - break; - case PLIST_REAL: - *((double *) value) = data->realval; - break; - case PLIST_STRING: - *((char **) value) = strdup(data->strval); - break; - case PLIST_UNICODE: - *((wchar_t **) value) = wcsdup(data->unicodeval); - break; - case PLIST_KEY: - *((char **) value) = strdup(data->strval); - break; - case PLIST_DATA: - case PLIST_ARRAY: - case PLIST_DICT: - case PLIST_DATE: - default: - break; - } -} - -plist_type plist_get_node_type(plist_t node) -{ - if (node && node->data) - return ((struct plist_data *) node->data)->type; - else - return PLIST_NONE; -} - -uint64_t plist_get_node_uint_val(plist_t node) -{ - if (PLIST_UINT == plist_get_node_type(node)) - return ((struct plist_data *) node->data)->intval; - else - return 0; -} diff --git a/src/plist.h b/src/plist.h deleted file mode 100644 index 1dc464a..0000000 --- a/src/plist.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * plist.h - * contains structures and the like for plists - * - * 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 PLIST_H -#define PLIST_H - -#include -#include - -#include -#include -#include -#include - - -typedef enum { - PLIST_BOOLEAN, - PLIST_UINT, - PLIST_REAL, - PLIST_STRING, - PLIST_UNICODE, - PLIST_ARRAY, - PLIST_DICT, - PLIST_DATE, - PLIST_DATA, - PLIST_KEY, - PLIST_NONE -} plist_type; - - -struct plist_data { - union { - char boolval; - uint64_t intval; - double realval; - char *strval; - wchar_t *unicodeval; - char *buff; - }; - uint64_t length; - plist_type type; -}; - - - -typedef GNode *plist_t; - - -void plist_new_dict(plist_t * plist); -void plist_new_array(plist_t * plist); -void plist_new_dict_in_plist(plist_t plist, plist_t * dict); -void plist_add_dict_element(plist_t dict, char *key, plist_type type, void *value, uint64_t length); -void plist_free(plist_t plist); - -void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); -void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); - -void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist); -void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist); - -plist_t find_query_node(plist_t plist, char *key, char *request); -plist_t find_node(plist_t plist, plist_type type, void *value); -void get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length); - -#endif diff --git a/src/xplist.c b/src/xplist.c deleted file mode 100644 index 2d650b4..0000000 --- a/src/xplist.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * plist.c - * XML plist implementation - * - * 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 "utils.h" -#include "plist.h" -#include -#include -#include - - -#include -#include - - -const char *plist_base = "\n\ -\n\ -\n\ -\0"; - - -/** Formats a block of text to be a given indentation and width. - * - * The total width of the return string will be depth + cols. - * - * @param buf The string to format. - * @param cols The number of text columns for returned block of text. - * @param depth The number of tabs to indent the returned block of text. - * - * @return The formatted string. - */ -char *format_string(const char *buf, int cols, int depth) -{ - int colw = depth + cols + 1; - int len = strlen(buf); - int nlines = len / cols + 1; - char *new_buf = (char *) malloc(nlines * colw + depth + 1); - int i = 0; - int j = 0; - - assert(cols >= 0); - assert(depth >= 0); - - // Inserts new lines and tabs at appropriate locations - for (i = 0; i < nlines; i++) { - new_buf[i * colw] = '\n'; - for (j = 0; j < depth; j++) - new_buf[i * colw + 1 + j] = '\t'; - memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols); - } - new_buf[len + (1 + depth) * nlines] = '\n'; - - // Inserts final row of indentation and termination character - for (j = 0; j < depth; j++) - new_buf[len + (1 + depth) * nlines + 1 + j] = '\t'; - new_buf[len + (1 + depth) * nlines + depth + 1] = '\0'; - - return new_buf; -} - - - -struct xml_node { - xmlNodePtr xml; - uint32_t depth; -}; - -/** Creates a new plist XML document. - * - * @return The plist XML document. - */ -xmlDocPtr new_xml_plist() -{ - char *plist = strdup(plist_base); - xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); - - if (!plist_xml) - return NULL; - - free(plist); - - return plist_xml; -} - -/** Destroys a previously created XML document. - * - * @param plist The XML document to destroy. - */ -void free_plist(xmlDocPtr plist) -{ - if (!plist) - return; - - xmlFreeDoc(plist); -} - -void node_to_xml(GNode * node, gpointer xml_struct) -{ - if (!node) - return; - - struct xml_node *xstruct = (struct xml_node *) xml_struct; - struct plist_data *node_data = (struct plist_data *) node->data; - - xmlNodePtr child_node = NULL; - char isStruct = FALSE; - - gchar *tag = NULL; - gchar *val = NULL; - - switch (node_data->type) { - case PLIST_BOOLEAN: - { - if (node_data->boolval) - tag = "true"; - else - tag = "false"; - } - break; - - case PLIST_UINT: - tag = "integer"; - val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); - break; - - case PLIST_REAL: - tag = "real"; - val = g_strdup_printf("%Lf", (long double) node_data->realval); - break; - - case PLIST_STRING: - tag = "string"; - val = g_strdup(node_data->strval); - break; - - case PLIST_UNICODE: - tag = "string"; - val = g_strdup((gchar *) node_data->unicodeval); - break; - - case PLIST_KEY: - tag = "key"; - val = g_strdup((gchar *) node_data->strval); - break; - - case PLIST_DATA: - tag = "data"; - gchar *valtmp = g_base64_encode(node_data->buff, node_data->length); - val = format_string(valtmp, 60, xstruct->depth); - g_free(valtmp); - break; - case PLIST_ARRAY: - tag = "array"; - isStruct = TRUE; - break; - case PLIST_DICT: - tag = "dict"; - isStruct = TRUE; - break; - case PLIST_DATE: //TODO : handle date tag - default: - break; - } - - int i = 0; - for (i = 0; i < xstruct->depth; i++) { - xmlNodeAddContent(xstruct->xml, "\t"); - } - child_node = xmlNewChild(xstruct->xml, NULL, tag, val); - xmlNodeAddContent(xstruct->xml, "\n"); - g_free(val); - - //add return for structured types - if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) - xmlNodeAddContent(child_node, "\n"); - - if (isStruct) { - struct xml_node child = { child_node, xstruct->depth + 1 }; - g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); - } - //fix indent for structured types - if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { - - for (i = 0; i < xstruct->depth; i++) { - xmlNodeAddContent(child_node, "\t"); - } - } - - return; -} - -void xml_to_node(xmlNodePtr xml_node, plist_t * plist_node) -{ - xmlNodePtr node = NULL; - - for (node = xml_node->children; node; node = node->next) { - - while (node && !xmlStrcmp(node->name, "text")) - node = node->next; - if (!node) - break; - - struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); - GNode *subnode = g_node_new(data); - if (*plist_node) - g_node_append(*plist_node, subnode); - else - *plist_node = subnode; - - if (!xmlStrcmp(node->name, "true")) { - data->boolval = 1; - data->type = PLIST_BOOLEAN; - continue; - } - - if (!xmlStrcmp(node->name, "false")) { - data->boolval = 0; - data->type = PLIST_BOOLEAN; - continue; - } - - if (!xmlStrcmp(node->name, "integer")) { - char *strval = xmlNodeGetContent(node); - data->intval = g_ascii_strtoull(strval, NULL, 0); - data->type = PLIST_UINT; - continue; - } - - if (!xmlStrcmp(node->name, "real")) { - char *strval = xmlNodeGetContent(node); - data->realval = atof(strval); - data->type = PLIST_REAL; - continue; - } - - if (!xmlStrcmp(node->name, "date")) - continue; //TODO : handle date tag - - if (!xmlStrcmp(node->name, "string")) { - data->strval = strdup(xmlNodeGetContent(node)); - data->type = PLIST_STRING; - continue; - } - - if (!xmlStrcmp(node->name, "key")) { - data->strval = strdup(xmlNodeGetContent(node)); - data->type = PLIST_KEY; - continue; - } - - if (!xmlStrcmp(node->name, "data")) { - gsize size = 0; - data->buff = g_base64_decode(xmlNodeGetContent(node), &size); - data->length = size; - data->type = PLIST_DATA; - continue; - } - - if (!xmlStrcmp(node->name, "array")) { - data->type = PLIST_ARRAY; - xml_to_node(node, &subnode); - continue; - } - - if (!xmlStrcmp(node->name, "dict")) { - data->type = PLIST_DICT; - xml_to_node(node, &subnode); - continue; - } - } -} - -void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) -{ - if (!plist || !plist_xml || *plist_xml) - return; - xmlDocPtr plist_doc = new_xml_plist(); - xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - struct xml_node root = { root_node, 0 }; - - node_to_xml(plist, &root); - - xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); -} - -void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) -{ - xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); - xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); - - xml_to_node(root_node, plist); -} -- cgit v1.1-32-gdbae From ef98ef7211bc6277e9a87349f0405957ab264936 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 8 Jan 2009 18:17:21 +0100 Subject: Perform proper goodby on lockdown shutdown. --- src/iphone.c | 59 +++++++++++++++++-- src/lockdown.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/lockdown.h | 1 + src/usbmux.c | 3 + src/utils.c | 34 +++++++++-- 5 files changed, 260 insertions(+), 15 deletions(-) diff --git a/src/iphone.c b/src/iphone.c index 32d27f6..1f68180 100644 --- a/src/iphone.c +++ b/src/iphone.c @@ -28,6 +28,49 @@ #include #include +/** + * This function sets the configuration of the given device to 3 + * and claims the interface 1. If usb_set_configuration fails, it detaches + * the kernel driver that blocks the device, and retries configuration. + * + * @param phone which device to configure + */ +static void iphone_config_usb_device(iphone_device_t phone) +{ + int ret; + + log_debug_msg("setting configuration... "); + ret = usb_set_configuration(phone->device, 3); + if (ret != 0) { + log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret)); + log_debug_msg("-> detaching kernel driver... "); + ret = + usb_detach_kernel_driver_np(phone->device, + phone->__device->config->interface->altsetting->bInterfaceNumber); + if (ret != 0) { + log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + log_debug_msg("setting configuration again... "); + ret = usb_set_configuration(phone->device, 3); + if (ret != 0) { + log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + } + } + } else { + log_debug_msg("done.\n"); + } + + log_debug_msg("claiming interface... "); + ret = usb_claim_interface(phone->device, 1); + if (ret != 0) { + log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret)); + } else { + log_debug_msg("done.\n"); + } +} /** * Given a USB bus and device number, returns a device handle to the iPhone on @@ -73,8 +116,7 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n, 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); + iphone_config_usb_device(phone); goto found; } @@ -115,9 +157,10 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n, return IPHONE_E_SUCCESS; } else { // Bad header + log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n"); + log_debug_buffer((char *) version, sizeof(*version)); iphone_free_device(phone); free(version); - log_debug_msg("get_iPhone(): Received a bad header/invalid version number."); return IPHONE_E_BAD_HEADER; } @@ -173,13 +216,21 @@ 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; + int bytes; + unsigned char buf[512]; + + // read final package + bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 1000); + if (bytes > 0) { + log_debug_msg("iphone_free_device: final read returned\n"); + log_debug_buffer(buf, bytes); + } 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; } diff --git a/src/lockdown.c b/src/lockdown.c index cf0d99e..ab168a3 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -92,6 +92,97 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone) return control; } +/** + * Closes the lockdownd communication session, by sending + * the StopSession Request to the device. + * + * @param control The lockdown client + */ +static void iphone_lckd_stop_session(iphone_lckd_client_t control) +{ + if (!control) + return; // IPHONE_E_INVALID_ARG; + xmlDocPtr plist = new_plist(); + xmlNode *dict, *key; + char **dictionary; + int bytes = 0, i = 0; + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + + log_debug_msg("lockdownd_stop_session() called\n"); + dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); + key = add_key_str_dict_element(plist, dict, "Request", "StopSession", 1); + key = add_key_str_dict_element(plist, dict, "SessionID", control->session_id, 1); + + char *XML_content; + uint32 length; + + xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); + ret = iphone_lckd_send(control, XML_content, length, &bytes); + + xmlFree(XML_content); + xmlFreeDoc(plist); + plist = NULL; + ret = iphone_lckd_recv(control, &XML_content, &bytes); + + plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); + if (!plist) { + fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n"); + return; //IPHONE_E_PLIST_ERROR; + } + dict = xmlDocGetRootElement(plist); + for (dict = dict->children; dict; dict = dict->next) { + if (!xmlStrcmp(dict->name, "dict")) + break; + } + if (!dict) { + fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_DICT_ERROR\n"); + return; //IPHONE_E_DICT_ERROR; + } + dictionary = read_dict_element_strings(dict); + xmlFreeDoc(plist); + free(XML_content); + + for (i = 0; dictionary[i]; i += 2) { + if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { + log_debug_msg("lockdownd_stop_session(): success\n"); + ret = IPHONE_E_SUCCESS; + break; + } + } + + free_dictionary(dictionary); + return; //ret; +} + +/** + * Shuts down the SSL session by first calling iphone_lckd_stop_session + * to cleanly close the lockdownd communication session, and then + * performing a close notify, which is done by "gnutls_bye". + * + * @param client The lockdown client + */ +static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client) +{ + if (!client) { + log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n"); + return; + } + + if (client->in_SSL) { + log_debug_msg("Stopping SSL Session\n"); + iphone_lckd_stop_session(client); + log_debug_msg("Sending SSL close notify\n"); + gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR); + } + if (client->ssl_session) { + gnutls_deinit(*client->ssl_session); + free(client->ssl_session); + } + client->in_SSL = 0; + client->gtls_buffer_hack_len = 0; // dunno if required?! + + return; +} /** Closes the lockdownd client and does the necessary housekeeping. * @@ -103,13 +194,17 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client) return IPHONE_E_INVALID_ARG; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + iphone_lckd_stop_SSL_session(client); + if (client->connection) { + lockdownd_close(client); + + // IMO, read of final "sessionUpcall connection closed" packet + // should come here instead of in iphone_free_device + ret = iphone_mux_free_client(client->connection); } - if (client->ssl_session) - gnutls_deinit(*client->ssl_session); - free(client->ssl_session); free(client); return ret; } @@ -520,6 +615,66 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch return ret; } +/** + * Performs the Goodbye Request to tell the device the communication + * session is now closed. + * + * @param control The lockdown client + */ +void lockdownd_close(iphone_lckd_client_t control) +{ + if (!control) + return; // IPHONE_E_INVALID_ARG; + xmlDocPtr plist = new_plist(); + xmlNode *dict, *key; + char **dictionary; + int bytes = 0, i = 0; + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + + log_debug_msg("lockdownd_close() called\n"); + dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); + key = add_key_str_dict_element(plist, dict, "Request", "Goodbye", 1); + char *XML_content; + uint32 length; + + xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); + ret = iphone_lckd_send(control, XML_content, length, &bytes); + + xmlFree(XML_content); + xmlFreeDoc(plist); + plist = NULL; + ret = iphone_lckd_recv(control, &XML_content, &bytes); + + plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); + if (!plist) { + fprintf(stderr, "lockdownd_close(): IPHONE_E_PLIST_ERROR\n"); + return; //IPHONE_E_PLIST_ERROR; + } + dict = xmlDocGetRootElement(plist); + for (dict = dict->children; dict; dict = dict->next) { + if (!xmlStrcmp(dict->name, "dict")) + break; + } + if (!dict) { + fprintf(stderr, "lockdownd_close(): IPHONE_E_DICT_ERROR\n"); + return; //IPHONE_E_DICT_ERROR; + } + dictionary = read_dict_element_strings(dict); + xmlFreeDoc(plist); + free(XML_content); + + for (i = 0; dictionary[i]; i += 2) { + if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { + log_debug_msg("lockdownd_close(): success\n"); + ret = IPHONE_E_SUCCESS; + break; + } + } + + free_dictionary(dictionary); + return; //ret; +} + /** Generates the device certificate from the public key as well as the host * and root certificates. * @@ -664,6 +819,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; // end variables + control->session_id[0] = '\0'; + key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); if (!key) { log_debug_msg("Couldn't add a key.\n"); @@ -699,6 +856,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c dictionary = read_dict_element_strings(dict); xmlFreeDoc(plist); free(what2send); + ret = IPHONE_E_SSL_ERROR; for (i = 0; dictionary[i]; i += 2) { if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { // Set up GnuTLS... @@ -741,8 +899,6 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c return_me = gnutls_handshake(*control->ssl_session); log_debug_msg("GnuTLS handshake done...\n"); - free_dictionary(dictionary); - if (return_me != GNUTLS_E_SUCCESS) { log_debug_msg("GnuTLS reported something wrong.\n"); gnutls_perror(return_me); @@ -750,10 +906,20 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c return IPHONE_E_SSL_ERROR; } else { control->in_SSL = 1; - return IPHONE_E_SUCCESS; + ret = IPHONE_E_SUCCESS; } + } else if (!strcmp(dictionary[i], "SessionID")) { + // we need to store the session ID for StopSession + strcpy(control->session_id, dictionary[i + 1]); + log_debug_msg("SessionID: %s\n", control->session_id); + free_dictionary(dictionary); + return ret; } } + if (ret == IPHONE_E_SUCCESS) { + log_debug_msg("Failed to get SessionID!\n"); + return ret; + } log_debug_msg("Apparently failed negotiating with lockdownd.\n"); log_debug_msg("Responding dictionary: \n"); diff --git a/src/lockdown.h b/src/lockdown.h index 79ca37e..8b4f27c 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -38,6 +38,7 @@ struct iphone_lckd_client_int { int in_SSL; char *gtls_buffer_hack; int gtls_buffer_hack_len; + char session_id[40]; }; char *lockdownd_generate_hostid(void); diff --git a/src/usbmux.c b/src/usbmux.c index 770d0db..c7ac7ef 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -182,8 +182,11 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) return IPHONE_E_INVALID_ARG; client->header->tcp_flags = 0x04; + client->header->length = htonl(0x1C); client->header->scnt = htonl(client->header->scnt); client->header->ocnt = htonl(client->header->ocnt); + client->header->window = 0; + client->header->length16 = htons(0x1C); int bytes = 0; bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); diff --git a/src/utils.c b/src/utils.c index 049777a..fb98471 100644 --- a/src/utils.c +++ b/src/utils.c @@ -46,7 +46,7 @@ void log_debug_msg(const char *format, ...) va_start(args, format); if (toto_debug) - fprintf(stderr, format, args); + vfprintf(stderr, format, args); va_end(args); @@ -56,11 +56,35 @@ void log_debug_msg(const char *format, ...) inline void log_debug_buffer(const char *data, const int length) { #ifndef STRIP_DEBUG_CODE + int i; + int j; + unsigned char c; - /* run the real fprintf */ - if (toto_debug) - fwrite(data, 1, length, stderr); - + if (toto_debug) { + for (i = 0; i < length; i += 16) { + fprintf(stderr, "%04x: ", i); + for (j = 0; j < 16; j++) { + if (i + j >= length) { + fprintf(stderr, " "); + continue; + } + fprintf(stderr, "%02hhx ", *(data + i + j)); + } + fprintf(stderr, " | "); + for (j = 0; j < 16; j++) { + if (i + j >= length) + break; + c = *(data + i + j); + if ((c < 32) || (c > 127)) { + fprintf(stderr, "."); + continue; + } + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); + } #endif } -- cgit v1.1-32-gdbae From 8f239549c124d11eb8899aec6c048d6a496e3911 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 8 Jan 2009 23:27:28 +0100 Subject: Implement skeleton of MobileSync protocol (handshake and goodbye). --- dev/Makefile.am | 6 +- src/Makefile.am | 2 +- src/MobileSync.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/MobileSync.h | 41 +++++++++++ src/lockdown.c | 16 ++--- 5 files changed, 264 insertions(+), 11 deletions(-) create mode 100644 src/MobileSync.c create mode 100644 src/MobileSync.h diff --git a/dev/Makefile.am b/dev/Makefile.am index d116581..7ca7e99 100644 --- a/dev/Makefile.am +++ b/dev/Makefile.am @@ -3,7 +3,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) -bin_PROGRAMS = iphoneclient lckd-client afccheck +bin_PROGRAMS = iphoneclient lckd-client afccheck msyncclient iphoneclient_SOURCES = main.c iphoneclient_LDADD = ../src/libiphone.la @@ -18,3 +18,7 @@ afccheck_CFLAGS = $(AM_CFLAGS) afccheck_LDFLAGS = $(AM_LDFLAGS) afccheck_LDADD = ../src/libiphone.la +msyncclient_SOURCES = msyncclient.c +msyncclient_CFLAGS = $(AM_CFLAGS) +msyncclient_LDFLAGS = $(AM_LDFLAGS) +msyncclient_LDADD = ../src/libiphone.la diff --git a/src/Makefile.am b/src/Makefile.am index 2514367..2e92fd1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,4 +12,4 @@ libiphone_initconf_LDFLAGS = $(libgthread2_LIBS) $(AM_LDFLAGS) lib_LTLIBRARIES = libiphone.la -libiphone_la_SOURCES = usbmux.c iphone.c lockdown.c AFC.c userpref.c utils.c +libiphone_la_SOURCES = usbmux.c iphone.c lockdown.c AFC.c userpref.c utils.c MobileSync.c diff --git a/src/MobileSync.c b/src/MobileSync.c new file mode 100644 index 0000000..2e574d2 --- /dev/null +++ b/src/MobileSync.c @@ -0,0 +1,210 @@ +/* + * MobileSync.c + * Contains functions for the built-in MobileSync client. + * + * Copyright (c) 2009 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 "MobileSync.h" +#include +#include + +#define MSYNC_VERSION_INT1 100 +#define MSYNC_VERSION_INT2 100 + +iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int dst_port, + iphone_msync_client_t * client) +{ + if (!device || src_port == 0 || dst_port == 0 || !client || *client) + return IPHONE_E_INVALID_ARG; + + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + + iphone_msync_client_t client_loc = (iphone_msync_client_t) malloc(sizeof(struct iphone_msync_client_int)); + + // 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; + } + //perform handshake + int bytes = 0; + char *content = NULL; + uint32_t length = 0; + plist_t array = NULL; + + //first receive version + ret = iphone_msync_recv(client_loc, &content, &bytes); + log_debug_msg("Receive msg :\nsize : %i\nbuffer :\n", bytes); + log_debug_buffer(content, bytes); + plist_from_bin(content, bytes, &array); + + free(content); + content = NULL; + + plist_t msg_node = + plist_find_node(array, PLIST_STRING, "DLMessageVersionExchange", strlen("DLMessageVersionExchange")); + plist_t ver_1 = plist_get_next_sibling(msg_node); + plist_t ver_2 = plist_get_next_sibling(ver_1); + + plist_type ver_1_type = plist_get_node_type(ver_1); + plist_type ver_2_type = plist_get_node_type(ver_2); + + if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) { + + uint64_t ver_1_val = 0; + uint64_t ver_2_val = 0; + + plist_get_uint_val(ver_1, &ver_1_val); + plist_get_uint_val(ver_2, &ver_2_val); + + plist_free(array); + array = NULL; + + if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1 + && ver_2_val == MSYNC_VERSION_INT2) { + + array = plist_new_array(); + plist_add_sub_string_el(array, "DLMessageVersionExchange"); + plist_add_sub_string_el(array, "DLVersionsOk"); + + plist_to_bin(array, &content, &length); + log_debug_msg("Send msg :\nsize : %i\nbuffer :\n", length); + log_debug_buffer(content, length); + ret = iphone_msync_send(client_loc, content, length, &bytes); + + free(content); + content = NULL; + plist_free(array); + array = NULL; + + ret = iphone_msync_recv(client_loc, &content, &bytes); + log_debug_msg("Receive msg :\nsize : %i\nbuffer :\n", bytes); + log_debug_buffer(content, bytes); + plist_from_bin(content, bytes, &array); + + free(content); + content = NULL; + + plist_t rep_node = + plist_find_node(array, PLIST_STRING, "DLMessageDeviceReady", strlen("DLMessageDeviceReady")); + + if (rep_node) { + ret = IPHONE_E_SUCCESS; + *client = client_loc; + } + } + } + + if (IPHONE_E_SUCCESS != ret) + iphone_msync_free_client(client_loc); + + return ret; +} + +static void iphone_msync_stop_session(iphone_msync_client_t client) +{ + if (!client) + return; + + int bytes = 0; + char *content = NULL; + uint32_t length = 0; + + plist_t array = plist_new_array(); + plist_add_sub_string_el(array, "DLMessageDisconnect"); + plist_add_sub_string_el(array, "All done, thanks for the memories"); + + plist_to_bin(array, &content, &length); + log_debug_msg("Send msg :\nsize : %i\nbuffer :\n", length); + log_debug_buffer(content, length); + iphone_msync_send(client, content, length, &bytes); + + free(content); + content = NULL; + plist_free(array); + array = NULL; +} + +void iphone_msync_free_client(iphone_msync_client_t client) +{ + iphone_msync_stop_session(client); + + iphone_mux_free_client(client->connection); +} + +/** Polls the iPhone for MobileSync data. + * + * @param client The MobileSync client + * @param dump_data The pointer to the location of the buffer in which to store + * the received data + * @param recv_byhtes The number of bytes received + * + * @return an error code + */ +iphone_error_t iphone_msync_recv(iphone_msync_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; + + ret = iphone_mux_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); + datalen = ntohl(datalen); + + receive = (char *) malloc(sizeof(char) * datalen); + ret = iphone_mux_recv(client->connection, receive, datalen, &bytes); + + *dump_data = receive; + *recv_bytes = bytes; + return ret; +} + +/** Sends MobileSync 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 client The MobileSync client + * @param raw_data The null terminated string buffer to send + * @param length The length of data to send + * @param sent_bytes The number of bytes sent + * + * @return an error code + */ +iphone_error_t iphone_msync_send(iphone_msync_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)); + + ret = iphone_mux_send(client->connection, real_query, ntohl(length) + sizeof(length), &bytes); + free(real_query); + *sent_bytes = bytes; + return ret; +} + diff --git a/src/MobileSync.h b/src/MobileSync.h new file mode 100644 index 0000000..d7c774e --- /dev/null +++ b/src/MobileSync.h @@ -0,0 +1,41 @@ +/* + * MobileSync.h + * Definitions for the built-in MobileSync client + * + * Copyright (c) 2009 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 MOBILESYNC_H +#define MOBILESYNC_H + +#include "usbmux.h" +#include "iphone.h" + +struct iphone_msync_client_int; +typedef struct iphone_msync_client_int *iphone_msync_client_t; + +struct iphone_msync_client_int { + iphone_umux_client_t connection; +}; + +iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int dst_port, + iphone_msync_client_t * client); +void iphone_msync_free_client(iphone_msync_client_t client); + +iphone_error_t iphone_msync_recv(iphone_msync_client_t client, char **dump_data, uint32_t * recv_bytes); +iphone_error_t iphone_msync_send(iphone_msync_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes); + +#endif diff --git a/src/lockdown.c b/src/lockdown.c index 872b7b0..56a6f4e 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -845,6 +845,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c ret = iphone_lckd_recv(control, &XML_content, &bytes); log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content); plist_from_xml(XML_content, bytes, &dict); + free(XML_content); + XML_content = NULL; if (!dict) return IPHONE_E_PLIST_ERROR; @@ -862,10 +864,6 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); plist_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; ret = IPHONE_E_SSL_ERROR; if (result_key_type == PLIST_KEY && result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { @@ -934,14 +932,14 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c // we need to store the session ID for StopSession strcpy(control->session_id, session_id); log_debug_msg("SessionID: %s\n", control->session_id); - return ret; } - } - - if (ret == IPHONE_E_SUCCESS) { + } else log_debug_msg("Failed to get SessionID!\n"); + plist_free(dict); + dict = NULL; + + if (ret == IPHONE_E_SUCCESS) return ret; - } log_debug_msg("Apparently failed negotiating with lockdownd.\n"); return IPHONE_E_SSL_ERROR; -- cgit v1.1-32-gdbae From d01cc63dc48349456b2d34cccab69d39eb1930cf Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 9 Jan 2009 17:51:01 +0100 Subject: add msync test client. --- dev/msyncclient.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 dev/msyncclient.c diff --git a/dev/msyncclient.c b/dev/msyncclient.c new file mode 100644 index 0000000..55d07c4 --- /dev/null +++ b/dev/msyncclient.c @@ -0,0 +1,73 @@ +/* + * msyncclient.c + * Rudimentary interface to the MobileSync iPhone + * + * Copyright (c) 2009 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 +#include "../src/MobileSync.h" + + +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; + } + + iphone_lckd_start_service(control, "com.apple.mobilesync", &port); + + if (port) { + iphone_msync_client_t msync = NULL; + iphone_msync_new_client(phone, 3432, port, &msync); + if (msync) + iphone_msync_free_client(msync); + } else { + printf("Start service failure.\n"); + } + + printf("All done.\n"); + + iphone_lckd_free_client(control); + iphone_free_device(phone); + + return 0; +} -- cgit v1.1-32-gdbae From bc2f3964851dff088dd47a08997e6c6730258834 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 9 Jan 2009 19:23:43 +0100 Subject: Improve logging mechanism. --- src/utils.c | 26 ++++++++++++++++++++++++++ src/utils.h | 8 ++++++++ 2 files changed, 34 insertions(+) diff --git a/src/utils.c b/src/utils.c index fb98471..988cb03 100644 --- a/src/utils.c +++ b/src/utils.c @@ -23,6 +23,7 @@ #include "utils.h" int toto_debug = 0; +uint16_t dbg_mask = 0; /** * Sets the level of debugging. Currently the only acceptable values are 0 and @@ -36,6 +37,15 @@ void iphone_set_debug(int level) } +/** + * Set debug ids to display. Values can be OR-ed + * + * @param level Set to 0 for no debugging or 1 for debugging. + */ +void iphone_set_debug_mask(uint16_t mask) +{ + dbg_mask = mask; +} void log_debug_msg(const char *format, ...) { @@ -53,6 +63,22 @@ void log_debug_msg(const char *format, ...) #endif } +void log_dbg_msg(uint16_t id, const char *format, ...) +{ +#ifndef STRIP_DEBUG_CODE + + if (id & dbg_mask) { + va_list args; + /* run the real fprintf */ + va_start(args, format); + + vfprintf(stderr, format, args); + + va_end(args); + } +#endif +} + inline void log_debug_buffer(const char *data, const int length) { #ifndef STRIP_DEBUG_CODE diff --git a/src/utils.h b/src/utils.h index 489f610..c1a8e54 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,7 +24,15 @@ #include "libiphone/libiphone.h" +#define DBGMASK_USBMUX (1 << 1) +#define DBGMASK_LOCKDOWND (1 << 2) +#define DBGMASK_MOBILESYNC (1 << 3) + +void iphone_set_debug_mask(uint16_t mask); + inline void log_debug_msg(const char *format, ...); +inline void log_dbg_msg(uint16_t id, const char *format, ...); + inline void log_debug_buffer(const char *data, const int length); inline void dump_debug_buffer(const char *file, const char *data, const int length); #endif -- cgit v1.1-32-gdbae From f3c08cfad0833d55a69ca3d54d9920a3cb558328 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Fri, 9 Jan 2009 19:24:27 +0100 Subject: Change msync recv and send functions to only deal with abstract plists. Start full address book dump function. Update to new logging mechanism. --- dev/msyncclient.c | 13 ++-- src/MobileSync.c | 179 +++++++++++++++++++++++++++++++++++++++++------------- src/MobileSync.h | 9 ++- 3 files changed, 150 insertions(+), 51 deletions(-) diff --git a/dev/msyncclient.c b/dev/msyncclient.c index 55d07c4..a6764b4 100644 --- a/dev/msyncclient.c +++ b/dev/msyncclient.c @@ -29,6 +29,7 @@ #include #include "../src/MobileSync.h" +#include "../src/utils.h" int main(int argc, char *argv[]) @@ -37,11 +38,9 @@ int main(int argc, char *argv[]) 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 (argc > 1 && !strcasecmp(argv[1], "--debug")) + iphone_set_debug_mask(DBGMASK_MOBILESYNC); + if (IPHONE_E_SUCCESS != iphone_get_device(&phone)) { printf("No iPhone found, is it plugged in?\n"); @@ -58,8 +57,10 @@ int main(int argc, char *argv[]) if (port) { iphone_msync_client_t msync = NULL; iphone_msync_new_client(phone, 3432, port, &msync); - if (msync) + if (msync) { + iphone_msync_get_all_contacts(msync); iphone_msync_free_client(msync); + } } else { printf("Start service failure.\n"); } diff --git a/src/MobileSync.c b/src/MobileSync.c index 2e574d2..ae22f4b 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -23,6 +23,7 @@ #include #include + #define MSYNC_VERSION_INT1 100 #define MSYNC_VERSION_INT2 100 @@ -44,19 +45,10 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int return ret; } //perform handshake - int bytes = 0; - char *content = NULL; - uint32_t length = 0; plist_t array = NULL; //first receive version - ret = iphone_msync_recv(client_loc, &content, &bytes); - log_debug_msg("Receive msg :\nsize : %i\nbuffer :\n", bytes); - log_debug_buffer(content, bytes); - plist_from_bin(content, bytes, &array); - - free(content); - content = NULL; + ret = iphone_msync_recv(client_loc, &array); plist_t msg_node = plist_find_node(array, PLIST_STRING, "DLMessageVersionExchange", strlen("DLMessageVersionExchange")); @@ -84,24 +76,12 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int plist_add_sub_string_el(array, "DLMessageVersionExchange"); plist_add_sub_string_el(array, "DLVersionsOk"); - plist_to_bin(array, &content, &length); - log_debug_msg("Send msg :\nsize : %i\nbuffer :\n", length); - log_debug_buffer(content, length); - ret = iphone_msync_send(client_loc, content, length, &bytes); + ret = iphone_msync_send(client_loc, array); - free(content); - content = NULL; plist_free(array); array = NULL; - ret = iphone_msync_recv(client_loc, &content, &bytes); - log_debug_msg("Receive msg :\nsize : %i\nbuffer :\n", bytes); - log_debug_buffer(content, bytes); - plist_from_bin(content, bytes, &array); - - free(content); - content = NULL; - + ret = iphone_msync_recv(client_loc, &array); plist_t rep_node = plist_find_node(array, PLIST_STRING, "DLMessageDeviceReady", strlen("DLMessageDeviceReady")); @@ -109,6 +89,9 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int ret = IPHONE_E_SUCCESS; *client = client_loc; } + plist_free(array); + array = NULL; + } } @@ -123,21 +106,11 @@ static void iphone_msync_stop_session(iphone_msync_client_t client) if (!client) return; - int bytes = 0; - char *content = NULL; - uint32_t length = 0; - plist_t array = plist_new_array(); plist_add_sub_string_el(array, "DLMessageDisconnect"); plist_add_sub_string_el(array, "All done, thanks for the memories"); - plist_to_bin(array, &content, &length); - log_debug_msg("Send msg :\nsize : %i\nbuffer :\n", length); - log_debug_buffer(content, length); - iphone_msync_send(client, content, length, &bytes); - - free(content); - content = NULL; + iphone_msync_send(client, array); plist_free(array); array = NULL; } @@ -158,9 +131,9 @@ void iphone_msync_free_client(iphone_msync_client_t client) * * @return an error code */ -iphone_error_t iphone_msync_recv(iphone_msync_client_t client, char **dump_data, uint32_t * recv_bytes) +iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist) { - if (!client || !dump_data || !recv_bytes) + if (!client || !plist || (plist && *plist)) return IPHONE_E_INVALID_ARG; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; char *receive; @@ -172,8 +145,14 @@ iphone_error_t iphone_msync_recv(iphone_msync_client_t client, char **dump_data, receive = (char *) malloc(sizeof(char) * datalen); ret = iphone_mux_recv(client->connection, receive, datalen, &bytes); - *dump_data = receive; - *recv_bytes = bytes; + plist_from_bin(receive, bytes, plist); + + char *XMLContent = NULL; + uint32_t length = 0; + plist_to_xml(*plist, &XMLContent, &length); + log_dbg_msg(DBGMASK_MOBILESYNC, "Recv msg :\nsize : %i\nbuffer :\n%s\n", length, XMLContent); + free(XMLContent); + return ret; } @@ -189,10 +168,22 @@ iphone_error_t iphone_msync_recv(iphone_msync_client_t client, char **dump_data, * * @return an error code */ -iphone_error_t iphone_msync_send(iphone_msync_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes) +iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist) { - if (!client || !raw_data || length == 0 || !sent_bytes) + if (!client || !plist) return IPHONE_E_INVALID_ARG; + + char *XMLContent = NULL; + uint32_t length = 0; + plist_to_xml(plist, &XMLContent, &length); + log_dbg_msg(DBGMASK_MOBILESYNC, "Send msg :\nsize : %i\nbuffer :\n%s\n", length, XMLContent); + free(XMLContent); + + char *content = NULL; + length = 0; + + plist_to_bin(plist, &content, &length); + char *real_query; int bytes; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; @@ -200,11 +191,113 @@ iphone_error_t iphone_msync_send(iphone_msync_client_t client, char *raw_data, u 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)); + memcpy(real_query + 4, content, ntohl(length)); ret = iphone_mux_send(client->connection, real_query, ntohl(length) + sizeof(length), &bytes); free(real_query); - *sent_bytes = bytes; return ret; } +iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client) +{ + if (!client) + return IPHONE_E_INVALID_ARG; + + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + plist_t array = NULL; + + array = plist_new_array(); + plist_add_sub_string_el(array, "SDMessageSyncDataClassWithDevice"); + plist_add_sub_string_el(array, "com.apple.Contacts"); + plist_add_sub_string_el(array, "---"); + plist_add_sub_string_el(array, "2009-01-09 18:03:58 +0100"); + plist_add_sub_uint_el(array, 106); + plist_add_sub_string_el(array, "___EmptyParameterString___"); + + ret = iphone_msync_send(client, array); + plist_free(array); + array = NULL; + + ret = iphone_msync_recv(client, &array); + + plist_t rep_node = plist_find_node(array, PLIST_STRING, "SDSyncTypeSlow", strlen("SDSyncTypeSlow")); + + if (!rep_node) + return ret; + + plist_free(array); + array = NULL; + + array = plist_new_array(); + plist_add_sub_string_el(array, "SDMessageGetAllRecordsFromDevice"); + plist_add_sub_string_el(array, "com.apple.Contacts"); + + + ret = iphone_msync_send(client, array); + plist_free(array); + array = NULL; + + ret = iphone_msync_recv(client, &array); + + plist_t contact_node; + plist_t switch_node; + + contact_node = plist_find_node(array, PLIST_STRING, "com.apple.Contacts", strlen("com.apple.Contacts")); + switch_node = + plist_find_node(array, PLIST_STRING, "SDMessageDeviceReadyToReceiveChanges", + strlen("SDMessageDeviceReadyToReceiveChanges")); + + while (NULL == switch_node) { + + plist_free(array); + array = NULL; + + array = plist_new_array(); + plist_add_sub_string_el(array, "SDMessageAcknowledgeChangesFromDevice"); + plist_add_sub_string_el(array, "com.apple.Contacts"); + + ret = iphone_msync_send(client, array); + plist_free(array); + array = NULL; + + ret = iphone_msync_recv(client, &array); + + contact_node = plist_find_node(array, PLIST_STRING, "com.apple.Contacts", strlen("com.apple.Contacts")); + switch_node = + plist_find_node(array, PLIST_STRING, "SDMessageDeviceReadyToReceiveChanges", + strlen("SDMessageDeviceReadyToReceiveChanges")); + } + + array = plist_new_array(); + plist_add_sub_string_el(array, "DLMessagePing"); + plist_add_sub_string_el(array, "Preparing to get changes for device"); + + ret = iphone_msync_send(client, array); + plist_free(array); + array = NULL; + + array = plist_new_array(); + plist_add_sub_string_el(array, "SDMessageProcessChanges"); + plist_add_sub_string_el(array, "com.apple.Contacts"); + plist_add_sub_node(array, plist_new_dict()); + plist_add_sub_bool_el(array, 0); + plist_t dict = plist_new_dict(); + plist_add_sub_node(array, dict); + plist_add_sub_key_el(dict, "SyncDeviceLinkEntityNamesKey"); + plist_t array2 = plist_new_array(); + plist_add_sub_string_el(array2, "com.apple.contacts.Contact"); + plist_add_sub_string_el(array2, "com.apple.contacts.Group"); + plist_add_sub_key_el(dict, "SyncDeviceLinkAllRecordsOfPulledEntityTypeSentKey"); + plist_add_sub_bool_el(dict, 0); + + ret = iphone_msync_send(client, array); + plist_free(array); + array = NULL; + + ret = iphone_msync_recv(client, &array); + plist_free(array); + array = NULL; + + + return ret; +} diff --git a/src/MobileSync.h b/src/MobileSync.h index d7c774e..b59547c 100644 --- a/src/MobileSync.h +++ b/src/MobileSync.h @@ -23,6 +23,9 @@ #include "usbmux.h" #include "iphone.h" +#include "utils.h" + +#include struct iphone_msync_client_int; typedef struct iphone_msync_client_int *iphone_msync_client_t; @@ -35,7 +38,9 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int iphone_msync_client_t * client); void iphone_msync_free_client(iphone_msync_client_t client); -iphone_error_t iphone_msync_recv(iphone_msync_client_t client, char **dump_data, uint32_t * recv_bytes); -iphone_error_t iphone_msync_send(iphone_msync_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes); +iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist); +iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist); + +iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client); #endif -- cgit v1.1-32-gdbae From 564aebf941f2f0c5fb57d2f86091b37d6331b9d9 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 12 Jan 2009 20:07:06 +0100 Subject: Update lockdownd transfer function to take abstract plist as argument. Simplify code accordingly. Use new libplist API to make code cleaner. --- dev/main.c | 3 + include/libiphone/libiphone.h | 5 +- src/lockdown.c | 617 ++++++++++++++++++++---------------------- src/utils.h | 2 + 4 files changed, 295 insertions(+), 332 deletions(-) diff --git a/dev/main.c b/dev/main.c index 4974eef..f865e52 100644 --- a/dev/main.c +++ b/dev/main.c @@ -28,6 +28,7 @@ #include #include +#include "../src/utils.h" int main(int argc, char *argv[]) @@ -38,8 +39,10 @@ int main(int argc, char *argv[]) if (argc > 1 && !strcasecmp(argv[1], "--debug")) { iphone_set_debug(1); + iphone_set_debug_mask(DBGMASK_ALL); } else { iphone_set_debug(0); + iphone_set_debug_mask(DBGMASK_NONE); } if (IPHONE_E_SUCCESS != iphone_get_device(&phone)) { diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index b3e3f95..aab7fdb 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -29,6 +29,7 @@ extern "C" { #include #include #include +#include //general errors #define IPHONE_E_SUCCESS 0 @@ -88,8 +89,8 @@ iphone_error_t iphone_lckd_new_client ( iphone_device_t device, iphone_lckd_clie 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 ); +iphone_error_t iphone_lckd_recv ( iphone_lckd_client_t client, plist_t* plist); +iphone_error_t iphone_lckd_send ( iphone_lckd_client_t client, plist_t plist); //usbmux related functions diff --git a/src/lockdown.c b/src/lockdown.c index 56a6f4e..b83b8cf 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -33,6 +33,7 @@ #include + const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { {"PKCS1", 536872976, 0}, {0, 1073741836, 0}, @@ -80,53 +81,49 @@ static void iphone_lckd_stop_session(iphone_lckd_client_t control) iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, PLIST_STRING, (void *) "StopSession", strlen("StopSession")); - plist_add_sub_element(dict, PLIST_KEY, (void *) "SessionID", strlen("SessionID")); - plist_add_sub_element(dict, PLIST_STRING, (void *) control->session_id, strlen(control->session_id)); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "StopSession"); + plist_add_sub_key_el(dict, "SessionID"); + plist_add_sub_string_el(dict, control->session_id); - log_debug_msg("iphone_lckd_stop_session() called\n"); - char *XML_content = NULL; - uint32_t length = 0; + log_dbg_msg(DBGMASK_LOCKDOWND, "iphone_lckd_stop_session() called\n"); - 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); + ret = iphone_lckd_send(control, dict); - 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); - plist_from_xml(XML_content, bytes, &dict); + ret = iphone_lckd_recv(control, &dict); if (!dict) { - log_debug_msg("lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n"); return; // IPHONE_E_PLIST_ERROR; } - plist_t query_node = plist_find_node(dict, PLIST_STRING, "StopSession", strlen("StopSession")); + plist_t query_node = plist_find_node_by_string(dict, "StopSession"); plist_t result_node = plist_get_next_sibling(query_node); plist_t value_node = plist_get_next_sibling(result_node); - plist_type result_type; - plist_type value_type; + plist_type result_type = plist_get_node_type(result_node); + plist_type value_type = plist_get_node_type(value_node); + + if (result_type == PLIST_KEY && value_type == PLIST_STRING) { - char *result_value = NULL; - char *value_value = NULL; - uint64_t result_length = 0; - uint64_t value_length = 0; + char *result_value = NULL; + char *value_value = NULL; - plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length); - plist_get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length); + plist_get_key_val(result_node, &result_value); + plist_get_string_val(value_node, &value_value); - if (result_type == PLIST_KEY && - value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { - log_debug_msg("lockdownd_stop_session(): success\n"); - ret = IPHONE_E_SUCCESS; + if (!strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_stop_session(): success\n"); + ret = IPHONE_E_SUCCESS; + } + free(result_value); + free(value_value); } + plist_free(dict); + dict = NULL; return; // ret; } @@ -142,14 +139,14 @@ static void iphone_lckd_stop_session(iphone_lckd_client_t control) static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client) { if (!client) { - log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_stop_SSL_session(): invalid argument!\n"); return; } if (client->in_SSL) { - log_debug_msg("Stopping SSL Session\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "Stopping SSL Session\n"); iphone_lckd_stop_session(client); - log_debug_msg("Sending SSL close notify\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "Sending SSL close notify\n"); gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR); } if (client->ssl_session) { @@ -196,9 +193,9 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client) * * @return The number of bytes received */ -iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, uint32_t * recv_bytes) +iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, plist_t * plist) { - if (!client || !dump_data || !recv_bytes) + if (!client || !plist || (plist && *plist)) return IPHONE_E_INVALID_ARG; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; char *receive; @@ -221,8 +218,18 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, u if (bytes > 0) ret = IPHONE_E_SUCCESS; } - *dump_data = receive; - *recv_bytes = bytes; + + if (bytes <= 0) { + free(receive); + return IPHONE_E_NOT_ENOUGH_DATA; + } + + plist_from_xml(receive, bytes, plist); + free(receive); + + if (!*plist) + ret = IPHONE_E_PLIST_ERROR; + return ret; } @@ -231,26 +238,31 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, u * @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 + * @param client The lockdownd client + * @param plist The plist to send * - * @return The number of bytes sent + * @return an error code (IPHONE_E_SUCCESS on success) */ -iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes) +iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, plist_t plist) { - if (!client || !raw_data || length == 0 || !sent_bytes) + if (!client || !plist) return IPHONE_E_INVALID_ARG; char *real_query; int bytes; + char *XMLContent = NULL; + uint32_t length = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + plist_to_xml(plist, &XMLContent, &length); + log_dbg_msg(DBGMASK_LOCKDOWND, "Send msg :\nsize : %i\nbuffer :\n%s\n", length, XMLContent); + + 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); + memcpy(real_query + 4, XMLContent, ntohl(length)); + free(XMLContent); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_send(): made the query, sending it along\n"); if (!client->in_SSL) ret = iphone_mux_send(client->connection, real_query, ntohl(length) + sizeof(length), &bytes); @@ -258,9 +270,9 @@ iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, char *raw_data, uin gnutls_record_send(*client->ssl_session, real_query, ntohl(length) + sizeof(length)); ret = IPHONE_E_SUCCESS; } - log_debug_msg("lockdownd_send(): sent it!\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_send(): sent it!\n"); free(real_query); - *sent_bytes = bytes; + return ret; } @@ -277,54 +289,49 @@ 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 = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, PLIST_STRING, (void *) "QueryType", strlen("QueryType")); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "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); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_hello() called\n"); + ret = iphone_lckd_send(control, dict); - 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); - plist_from_xml(XML_content, bytes, &dict); + ret = iphone_lckd_recv(control, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; + if (IPHONE_E_SUCCESS != ret) + return ret; - plist_t query_node = plist_find_node(dict, PLIST_STRING, "QueryType", strlen("QueryType")); + plist_t query_node = plist_find_node_by_string(dict, "QueryType"); plist_t result_node = plist_get_next_sibling(query_node); plist_t value_node = plist_get_next_sibling(result_node); - plist_type result_type; - plist_type value_type; + plist_type result_type = plist_get_node_type(result_node); + plist_type value_type = plist_get_node_type(value_node); + + if (result_type == PLIST_KEY && value_type == PLIST_STRING) { - char *result_value = NULL; - char *value_value = NULL; - uint64_t result_length = 0; - uint64_t value_length = 0; + char *result_value = NULL; + char *value_value = NULL; - plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length); - plist_get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length); + plist_get_key_val(result_node, &result_value); + plist_get_string_val(value_node, &value_value); - 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; + if (!strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_hello(): success\n"); + ret = IPHONE_E_SUCCESS; + } + free(result_value); + free(value_value); } + plist_free(dict); + dict = NULL; + return ret; } @@ -343,25 +350,18 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c 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 */ dict = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) req_key, strlen(req_key)); - plist_add_sub_element(dict, PLIST_STRING, (void *) req_string, strlen(req_string)); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, PLIST_STRING, (void *) "GetValue", strlen("GetValue")); - plist_to_xml(dict, &XML_content, &length); + plist_add_sub_key_el(dict, req_key); + plist_add_sub_string_el(dict, req_string); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "GetValue"); /* send to iPhone */ - log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content); - ret = iphone_lckd_send(control, XML_content, length, &bytes); + ret = iphone_lckd_send(control, dict); - free(XML_content); - XML_content = NULL; plist_free(dict); dict = NULL; @@ -369,61 +369,65 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c 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); + ret = iphone_lckd_recv(control, &dict); if (ret != IPHONE_E_SUCCESS) return ret; - plist_from_xml(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = plist_find_node(dict, PLIST_STRING, "GetValue", strlen("GetValue")); + plist_t query_node = plist_find_node_by_string(dict, "GetValue"); plist_t result_key_node = plist_get_next_sibling(query_node); plist_t result_value_node = plist_get_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; + plist_type result_key_type = plist_get_node_type(result_key_node); + plist_type result_value_type = plist_get_node_type(result_value_node); - plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &result_length); - plist_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) { - 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; - } + char *result_key = NULL; + char *result_value = NULL; + ret = IPHONE_E_DICT_ERROR; + + plist_get_key_val(result_key_node, &result_key); + plist_get_string_val(result_value_node, &result_value); + if (!strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_generic_get_value(): success\n"); + ret = IPHONE_E_SUCCESS; + } + free(result_key); + free(result_value); + } if (ret != IPHONE_E_SUCCESS) { - return IPHONE_E_DICT_ERROR; + return ret; } plist_t value_key_node = plist_get_next_sibling(result_key_node); plist_t value_value_node = plist_get_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; - - plist_get_type_and_value(value_key_node, &value_key_type, (void *) (&value_key), &key_length); - plist_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_type value_key_type = plist_get_node_type(value_key_node); + + if (value_key_type == PLIST_KEY) { + + char *result_key = NULL; + plist_get_key_val(value_key_node, &result_key); + + if (!strcmp(result_key, "Value")) { + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_generic_get_value(): success\n"); + + plist_type value_value_type; + char *value_value = NULL; + uint64_t valval_length = 0; + + plist_get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value), &valval_length); + + value->data = value_value; + value->size = valval_length; + ret = IPHONE_E_SUCCESS; + } + free(result_key); } plist_free(dict); - free(XML_content); return ret; } @@ -520,9 +524,6 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch 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 }; @@ -543,25 +544,22 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch /* Setup Pair request plist */ dict = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "PairRecord", strlen("PairRecord")); - dict_record = plist_add_sub_element(dict, PLIST_DICT, NULL, 0); - plist_add_sub_element(dict_record, PLIST_KEY, (void *) "DeviceCertificate", strlen("DeviceCertificate")); - plist_add_sub_element(dict_record, PLIST_DATA, (void *) device_cert.data, device_cert.size); - plist_add_sub_element(dict_record, PLIST_KEY, (void *) "HostCertificate", strlen("HostCertificate")); - plist_add_sub_element(dict_record, PLIST_DATA, (void *) host_cert.data, host_cert.size); - plist_add_sub_element(dict_record, PLIST_KEY, (void *) "HostID", strlen("HostID")); - plist_add_sub_element(dict_record, PLIST_STRING, (void *) host_id, strlen(host_id)); - plist_add_sub_element(dict_record, PLIST_KEY, (void *) "RootCertificate", strlen("RootCertificate")); - plist_add_sub_element(dict_record, PLIST_DATA, (void *) root_cert.data, root_cert.size); - plist_add_sub_element(dict_record, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict_record, 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); + plist_add_sub_key_el(dict, "PairRecord"); + dict_record = plist_new_dict(); + plist_add_sub_node(dict, dict_record); + plist_add_sub_key_el(dict_record, "DeviceCertificate"); + plist_add_sub_data_el(dict_record, device_cert.data, device_cert.size); + plist_add_sub_key_el(dict_record, "HostCertificate"); + plist_add_sub_data_el(dict_record, host_cert.data, host_cert.size); + plist_add_sub_key_el(dict_record, "HostID"); + plist_add_sub_string_el(dict_record, host_id); + plist_add_sub_key_el(dict_record, "RootCertificate"); + plist_add_sub_data_el(dict_record, root_cert.data, root_cert.size); + plist_add_sub_key_el(dict_record, "Request"); + plist_add_sub_string_el(dict_record, "Pair"); /* send to iPhone */ - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); + ret = iphone_lckd_send(control, dict); plist_free(dict); dict = NULL; @@ -569,45 +567,43 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch return ret; /* Now get iPhone's answer */ - ret = iphone_lckd_recv(control, &XML_content, &bytes); + ret = iphone_lckd_recv(control, &dict); 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"); - - plist_from_xml(XML_content, bytes, &dict); - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = plist_find_node(dict, PLIST_STRING, "Pair", strlen("Pair")); + plist_t query_node = plist_find_node_by_string(dict, "Pair"); plist_t result_key_node = plist_get_next_sibling(query_node); plist_t result_value_node = plist_get_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; + plist_type result_key_type = plist_get_node_type(result_key_node); + plist_type result_value_type = plist_get_node_type(result_value_node); - plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); - plist_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) { - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { - ret = IPHONE_E_SUCCESS; + char *result_key = NULL; + char *result_value = NULL; + + plist_get_key_val(result_key_node, &result_key); + plist_get_string_val(result_value_node, &result_value); + + if (!strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { + ret = IPHONE_E_SUCCESS; + } + + free(result_key); + free(result_value); } + plist_free(dict); + dict = NULL; /* store public key in config if pairing succeeded */ if (ret == IPHONE_E_SUCCESS) { - log_debug_msg("lockdownd_pair_device: pair success\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "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"); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_pair_device: pair failure\n"); ret = IPHONE_E_PAIRING_FAILED; } free(public_key.data); @@ -625,56 +621,48 @@ void lockdownd_close(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 = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, PLIST_STRING, (void *) "Goodbye", strlen("Goodbye")); - - log_debug_msg("lockdownd_close() called\n"); - char *XML_content = NULL; - uint32_t length = 0; + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "Goodbye"); - 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); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_close() called\n"); - free(XML_content); - XML_content = NULL; + ret = iphone_lckd_send(control, dict); 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); - plist_from_xml(XML_content, bytes, &dict); + ret = iphone_lckd_recv(control, &dict); if (!dict) { - log_debug_msg("lockdownd_close(): IPHONE_E_PLIST_ERROR\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_close(): IPHONE_E_PLIST_ERROR\n"); return; // IPHONE_E_PLIST_ERROR; } - plist_t query_node = plist_find_node(dict, PLIST_STRING, "Goodbye", strlen("Goodbye")); + plist_t query_node = plist_find_node_by_string(dict, "Goodbye"); plist_t result_node = plist_get_next_sibling(query_node); plist_t value_node = plist_get_next_sibling(result_node); - plist_type result_type; - plist_type value_type; + plist_type result_type = plist_get_node_type(result_node); + plist_type value_type = plist_get_node_type(value_node); - char *result_value = NULL; - char *value_value = NULL; - uint64_t result_length = 0; - uint64_t value_length = 0; + if (result_type == PLIST_KEY && value_type == PLIST_STRING) { + char *result_value = NULL; + char *value_value = NULL; - plist_get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length); - plist_get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length); + plist_get_key_val(result_node, &result_value); + plist_get_string_val(value_node, &value_value); - if (result_type == PLIST_KEY && - value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { - log_debug_msg("lockdownd_close(): success\n"); - ret = IPHONE_E_SUCCESS; + if (!strcmp(result_value, "Result") && !strcmp(value_value, "Success")) { + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_close(): success\n"); + ret = IPHONE_E_SUCCESS; + } + free(result_value); + free(value_value); } - + plist_free(dict); + dict = NULL; return; // ret; } @@ -824,54 +812,44 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c /* Setup DevicePublicKey request plist */ dict = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "HostID", strlen("HostID")); - plist_add_sub_element(dict, PLIST_STRING, (void *) HostID, strlen(HostID)); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, 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); + plist_add_sub_key_el(dict, "HostID"); + plist_add_sub_string_el(dict, HostID); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "StartSession"); - ret = iphone_lckd_send(control, XML_content, length, &bytes); - - free(XML_content); - XML_content = NULL; + ret = iphone_lckd_send(control, dict); 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); - plist_from_xml(XML_content, bytes, &dict); - free(XML_content); - XML_content = NULL; - if (!dict) - return IPHONE_E_PLIST_ERROR; - - plist_t query_node = plist_find_node(dict, PLIST_STRING, "StartSession", strlen("StartSession")); - plist_t result_key_node = plist_get_next_sibling(query_node); - plist_t result_value_node = plist_get_next_sibling(result_key_node); - - plist_type result_key_type; - plist_type result_value_type; + ret = iphone_lckd_recv(control, &dict); + + if (!dict) + return IPHONE_E_PLIST_ERROR; + + plist_t query_node = plist_find_node(dict, PLIST_STRING, "StartSession", strlen("StartSession")); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_next_sibling(result_key_node); + + plist_type result_key_type = plist_get_node_type(result_key_node); + plist_type result_value_type = plist_get_node_type(result_value_node); + + if (result_key_type == PLIST_KEY && result_value_type == PLIST_STRING) { char *result_key = NULL; char *result_value = NULL; - uint64_t key_length = 0; - uint64_t val_length = 0; - plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length); - plist_get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length); + plist_get_key_val(result_key_node, &result_key); + plist_get_string_val(result_value_node, &result_value); ret = IPHONE_E_SSL_ERROR; - if (result_key_type == PLIST_KEY && - result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) { + if (!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"); + log_dbg_msg(DBGMASK_LOCKDOWND, "We started the session OK, now trying GnuTLS\n"); errno = 0; gnutls_global_init(); //gnutls_anon_allocate_client_credentials(&anoncred); @@ -894,59 +872,59 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c } gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me. - log_debug_msg("GnuTLS step 1...\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "GnuTLS step 1...\n"); gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control); - log_debug_msg("GnuTLS step 2...\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "GnuTLS step 2...\n"); gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func) & lockdownd_secuwrite); - log_debug_msg("GnuTLS step 3...\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "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"); + log_dbg_msg(DBGMASK_LOCKDOWND, "GnuTLS step 4 -- now handshaking...\n"); if (errno) - log_debug_msg("WARN: errno says %s before handshake!\n", strerror(errno)); + log_dbg_msg(DBGMASK_LOCKDOWND, "WARN: errno says %s before handshake!\n", strerror(errno)); return_me = gnutls_handshake(*control->ssl_session); - log_debug_msg("GnuTLS handshake done...\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "GnuTLS handshake done...\n"); if (return_me != GNUTLS_E_SUCCESS) { - log_debug_msg("GnuTLS reported something wrong.\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "GnuTLS reported something wrong.\n"); gnutls_perror(return_me); - log_debug_msg("oh.. errno says %s\n", strerror(errno)); + log_dbg_msg(DBGMASK_LOCKDOWND, "oh.. errno says %s\n", strerror(errno)); return IPHONE_E_SSL_ERROR; } else { control->in_SSL = 1; ret = IPHONE_E_SUCCESS; } } - //store session id - plist_t session_node = plist_find_node(dict, PLIST_KEY, "SessionID", strlen("SessionID")); - if (session_node) { + } + //store session id + plist_t session_node = plist_find_node_by_key(dict, "SessionID"); + if (session_node) { + + plist_t session_node_val = plist_get_next_sibling(session_node); + plist_type session_node_val_type = plist_get_node_type(session_node_val); + + if (session_node_val_type == PLIST_STRING) { - plist_type session_node_val_type; char *session_id = NULL; - uint64_t session_id_length = 0; - plist_t session_node_val = plist_get_next_sibling(session_node); + plist_get_string_val(session_node_val, &session_id); - plist_get_type_and_value(session_node_val, &session_node_val_type, (void *) (&session_id), - &session_id_length); - if (session_node_val_type == PLIST_STRING && session_id_length > 0) { + if (session_node_val_type == PLIST_STRING && session_id) { // we need to store the session ID for StopSession strcpy(control->session_id, session_id); - log_debug_msg("SessionID: %s\n", control->session_id); + log_dbg_msg(DBGMASK_LOCKDOWND, "SessionID: %s\n", control->session_id); } - } else - log_debug_msg("Failed to get SessionID!\n"); - plist_free(dict); - dict = NULL; + free(session_id); + } + } else + log_dbg_msg(DBGMASK_LOCKDOWND, "Failed to get SessionID!\n"); + plist_free(dict); + dict = NULL; - if (ret == IPHONE_E_SUCCESS) - return ret; + if (ret == IPHONE_E_SUCCESS) + return ret; - log_debug_msg("Apparently failed negotiating with lockdownd.\n"); - return IPHONE_E_SSL_ERROR; - } else { - log_debug_msg("Didn't get enough bytes.\n"); - return IPHONE_E_NOT_ENOUGH_DATA; - } + log_dbg_msg(DBGMASK_LOCKDOWND, "Apparently failed negotiating with lockdownd.\n"); + return IPHONE_E_SSL_ERROR; } /** gnutls callback for writing data to the iPhone. @@ -962,10 +940,10 @@ ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size 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); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_secuwrite() called\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "pre-send\nlength = %zi\n", length); iphone_mux_send(control->connection, buffer, length, &bytes); - log_debug_msg("post-send\nsent %i bytes\n", bytes); + log_dbg_msg(DBGMASK_LOCKDOWND, "post-send\nsent %i bytes\n", bytes); dump_debug_buffer("sslpacketwrite.out", buffer, length); return bytes; @@ -985,7 +963,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ char *hackhackhack = NULL; iphone_lckd_client_t control; control = (iphone_lckd_client_t) transport; - log_debug_msg("lockdownd_securead() called\nlength = %zi\n", length); + log_dbg_msg(DBGMASK_LOCKDOWND, "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 @@ -994,7 +972,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ 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"); + log_dbg_msg(DBGMASK_LOCKDOWND, "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 @@ -1003,33 +981,34 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ 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); + log_dbg_msg(DBGMASK_LOCKDOWND, "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"); + log_dbg_msg(DBGMASK_LOCKDOWND, "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); + log_dbg_msg(DBGMASK_LOCKDOWND, "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); + log_dbg_msg(DBGMASK_LOCKDOWND, "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)); + log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_securead(): uh oh\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, + "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"); + log_dbg_msg(DBGMASK_LOCKDOWND, + "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; @@ -1045,10 +1024,11 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ memcpy(buffer + pos_start_fill, recv_buffer, length); free(recv_buffer); if (bytes == length) { - log_debug_msg("Returning how much we received.\n"); + log_dbg_msg(DBGMASK_LOCKDOWND, "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); + log_dbg_msg(DBGMASK_LOCKDOWND, "Returning what they want to hear.\nHack length: %i\n", + control->gtls_buffer_hack_len); return length; } } @@ -1073,95 +1053,72 @@ iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char 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; + uint32_t port_loc = 0; iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; free(host_id); host_id = NULL; dict = plist_new_dict(); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Request", strlen("Request")); - plist_add_sub_element(dict, PLIST_STRING, (void *) "StartService", strlen("StartService")); - plist_add_sub_element(dict, PLIST_KEY, (void *) "Service", strlen("Service")); - plist_add_sub_element(dict, PLIST_STRING, (void *) service, strlen(service)); - plist_to_xml(dict, &XML_content, &length); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "StartService"); + plist_add_sub_key_el(dict, "Service"); + plist_add_sub_string_el(dict, service); /* 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; + ret = iphone_lckd_send(client, dict); plist_free(dict); dict = NULL; if (IPHONE_E_SUCCESS != ret) return ret; - ret = iphone_lckd_recv(client, &XML_content, &bytes); + ret = iphone_lckd_recv(client, &dict); if (IPHONE_E_SUCCESS != ret) return ret; - plist_from_xml(XML_content, bytes, &dict); if (!dict) return IPHONE_E_PLIST_ERROR; + plist_t query_node = plist_find_node_by_string(dict, "StartService"); + plist_t result_key_node = plist_get_next_sibling(query_node); + plist_t result_value_node = plist_get_next_sibling(result_key_node); - if (bytes <= 0) - return IPHONE_E_NOT_ENOUGH_DATA; - else { + plist_t port_key_node = plist_find_node_by_key(dict, "Port"); + plist_t port_value_node = plist_get_next_sibling(port_key_node); - plist_t query_node = plist_find_node(dict, PLIST_STRING, "StartService", strlen("StartService")); - plist_t result_key_node = plist_get_next_sibling(query_node); - plist_t result_value_node = plist_get_next_sibling(result_key_node); + plist_type result_key_type = plist_get_node_type(result_key_node); + plist_type result_value_type = plist_get_node_type(result_value_node); + plist_type port_key_type = plist_get_node_type(port_key_node); + plist_type port_value_type = plist_get_node_type(port_value_node); - plist_t port_key_node = plist_find_node(dict, PLIST_KEY, "Port", strlen("Port")); - plist_t port_value_node = plist_get_next_sibling(port_key_node); + if (result_key_type == PLIST_KEY && result_value_type == PLIST_STRING && port_key_type == PLIST_KEY + && port_value_type == PLIST_UINT) { - 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; - plist_get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &res_key_length); - plist_get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &res_val_length); - plist_get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key), &port_key_length); - plist_get_type_and_value(port_value_node, &port_value_type, (void *) (&port_value), &port_val_length); + plist_get_key_val(result_key_node, &result_key); + plist_get_string_val(result_value_node, &result_value); + plist_get_key_val(port_key_node, &port_key); + plist_get_uint_val(port_value_node, &port_value); - 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")) { + if (!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) { + if (port && ret == IPHONE_E_SUCCESS) *port = port_loc; - return IPHONE_E_SUCCESS; - } else - return IPHONE_E_UNKNOWN_ERROR; + else + ret = IPHONE_E_UNKNOWN_ERROR; } - return IPHONE_E_UNKNOWN_ERROR; + plist_free(dict); + dict = NULL; + return ret; } diff --git a/src/utils.h b/src/utils.h index c1a8e54..d9a441d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,6 +24,8 @@ #include "libiphone/libiphone.h" +#define DBGMASK_ALL 0xFFFF +#define DBGMASK_NONE 0x0000 #define DBGMASK_USBMUX (1 << 1) #define DBGMASK_LOCKDOWND (1 << 2) #define DBGMASK_MOBILESYNC (1 << 3) -- cgit v1.1-32-gdbae From d4694679f918750e920a2238d891cd2fbb741a90 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Tue, 13 Jan 2009 18:57:52 +0100 Subject: Add parts of a python binding to libiphone that also include libplist (using SWIG). --- Makefile.am | 4 +- autogen.sh | 2 +- configure.ac | 8 +- include/libiphone/libiphone.h | 11 ++ m4/ac_pkg_swig.m4 | 122 +++++++++++++++++++ m4/ac_python_devel.m4 | 265 ++++++++++++++++++++++++++++++++++++++++++ m4/swig_python.m4 | 65 +++++++++++ src/MobileSync.c | 4 +- src/MobileSync.h | 9 +- swig/Makefile.am | 18 +++ swig/__init__.py | 1 + swig/iphone.i | 123 ++++++++++++++++++++ 12 files changed, 618 insertions(+), 14 deletions(-) create mode 100644 m4/ac_pkg_swig.m4 create mode 100644 m4/ac_python_devel.m4 create mode 100644 m4/swig_python.m4 create mode 100644 swig/Makefile.am create mode 100644 swig/__init__.py create mode 100644 swig/iphone.i diff --git a/Makefile.am b/Makefile.am index f103377..982f42b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign - -SUBDIRS = src include fdi $(DEV_SUB) +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src include fdi swig $(DEV_SUB) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libiphone-1.0.pc diff --git a/autogen.sh b/autogen.sh index c17ea96..9aa7170 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,5 @@ #!/bin/sh -aclocal +aclocal -I m4 libtoolize autoheader automake --add-missing diff --git a/configure.ac b/configure.ac index 9516ec4..87ed8dc 100644 --- a/configure.ac +++ b/configure.ac @@ -6,9 +6,15 @@ AC_INIT(libiphone, 0.1.0, nospam@nowhere.com) AM_INIT_AUTOMAKE(libiphone, 0.1.0) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([m4]) AC_PROG_LIBTOOL +AM_PATH_PYTHON(2.3) +AC_PROG_SWIG(1.3.21) +SWIG_PYTHON + + # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O @@ -60,4 +66,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 fdi/Makefile dev/Makefile swig/Makefile libiphone-1.0.pc) diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index aab7fdb..59d2de2 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -78,6 +78,9 @@ 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; +struct iphone_msync_client_int; +typedef struct iphone_msync_client_int *iphone_msync_client_t; + //device related functions void iphone_set_debug(int level); iphone_error_t iphone_get_device ( iphone_device_t *device ); @@ -120,6 +123,14 @@ iphone_error_t iphone_afc_rename_file ( iphone_afc_client_t client, const char * iphone_error_t iphone_afc_mkdir ( iphone_afc_client_t client, const char *dir); + +iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int dst_port, + iphone_msync_client_t * client); +iphone_error_t iphone_msync_free_client(iphone_msync_client_t client); + +iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist); +iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist); + #ifdef __cplusplus } #endif diff --git a/m4/ac_pkg_swig.m4 b/m4/ac_pkg_swig.m4 new file mode 100644 index 0000000..738f69d --- /dev/null +++ b/m4/ac_pkg_swig.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ac_pkg_swig.html +# =========================================================================== +# +# SYNOPSIS +# +# AC_PROG_SWIG([major.minor.micro]) +# +# DESCRIPTION +# +# This macro searches for a SWIG installation on your system. If found you +# should call SWIG via $(SWIG). You can use the optional first argument to +# check if the version of the available SWIG is greater than or equal to +# the value of the argument. It should have the format: N[.N[.N]] (N is a +# number between 0 and 999. Only the first N is mandatory.) +# +# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks that +# the swig package is this version number or higher. +# +# In configure.in, use as: +# +# AC_PROG_SWIG(1.3.17) +# SWIG_ENABLE_CXX +# SWIG_MULTI_MODULE_SUPPORT +# SWIG_PYTHON +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Sebastian Huber +# Copyright (c) 2008 Alan W. Irwin +# Copyright (c) 2008 Rafael Laboissiere +# Copyright (c) 2008 Andrew Collier +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AC_PROG_SWIG],[ + AC_PATH_PROG([SWIG],[swig]) + if test -z "$SWIG" ; then + AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org]) + SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false' + elif test -n "$1" ; then + AC_MSG_CHECKING([for SWIG version]) + [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`] + AC_MSG_RESULT([$swig_version]) + if test -n "$swig_version" ; then + # Calculate the required version number components + [required=$1] + [required_major=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_major" ; then + [required_major=0] + fi + [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] + [required_minor=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_minor" ; then + [required_minor=0] + fi + [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] + [required_patch=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_patch" ; then + [required_patch=0] + fi + # Calculate the available version number components + [available=$swig_version] + [available_major=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_major" ; then + [available_major=0] + fi + [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] + [available_minor=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_minor" ; then + [available_minor=0] + fi + [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] + [available_patch=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_patch" ; then + [available_patch=0] + fi + if test $available_major -ne $required_major \ + -o $available_minor -ne $required_minor \ + -o $available_patch -lt $required_patch ; then + AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org]) + SWIG='echo "Error: SWIG version >= $1 is required. You have '"$swig_version"'. You should look at http://www.swig.org" ; false' + else + AC_MSG_NOTICE([SWIG executable is '$SWIG']) + SWIG_LIB=`$SWIG -swiglib` + AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB']) + fi + else + AC_MSG_WARN([cannot determine SWIG version]) + SWIG='echo "Error: Cannot determine SWIG version. You should look at http://www.swig.org" ; false' + fi + fi + AC_SUBST([SWIG_LIB]) +]) diff --git a/m4/ac_python_devel.m4 b/m4/ac_python_devel.m4 new file mode 100644 index 0000000..7cec10f --- /dev/null +++ b/m4/ac_python_devel.m4 @@ -0,0 +1,265 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ac_python_devel.html +# =========================================================================== +# +# SYNOPSIS +# +# AC_PYTHON_DEVEL([version]) +# +# DESCRIPTION +# +# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it +# in your configure.ac. +# +# This macro checks for Python and tries to get the include path to +# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS) +# output variables. It also exports $(PYTHON_EXTRA_LIBS) and +# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code. +# +# You can search for some particular version of Python by passing a +# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please +# note that you *have* to pass also an operator along with the version to +# match, and pay special attention to the single quotes surrounding the +# version number. Don't use "PYTHON_VERSION" for this: that environment +# variable is declared as precious and thus reserved for the end-user. +# +# This macro should work for all versions of Python >= 2.1.0. As an end +# user, you can disable the check for the python version by setting the +# PYTHON_NOVERSIONCHECK environment variable to something else than the +# empty string. +# +# If you need to use this macro for an older Python version, please +# contact the authors. We're always open for feedback. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Sebastian Huber +# Copyright (c) 2008 Alan W. Irwin +# Copyright (c) 2008 Rafael Laboissiere +# Copyright (c) 2008 Andrew Collier +# Copyright (c) 2008 Matteo Settenvini +# Copyright (c) 2008 Horst Knorr +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AC_PYTHON_DEVEL],[ + # + # Allow the use of a (user set) custom python version + # + AC_ARG_VAR([PYTHON_VERSION],[The installed Python + version to use, for example '2.3'. This string + will be appended to the Python interpreter + canonical name.]) + + AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) + if test -z "$PYTHON"; then + AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) + PYTHON_VERSION="" + fi + + # + # Check for a version of Python >= 2.1.0 + # + AC_MSG_CHECKING([for a version of Python >= '2.1.0']) + ac_supports_python_ver=`$PYTHON -c "import sys, string; \ + ver = string.split(sys.version)[[0]]; \ + print ver >= '2.1.0'"` + if test "$ac_supports_python_ver" != "True"; then + if test -z "$PYTHON_NOVERSIONCHECK"; then + AC_MSG_RESULT([no]) + AC_MSG_FAILURE([ +This version of the AC@&t@_PYTHON_DEVEL macro +doesn't work properly with versions of Python before +2.1.0. You may need to re-run configure, setting the +variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, +PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. +Moreover, to disable this check, set PYTHON_NOVERSIONCHECK +to something else than an empty string. +]) + else + AC_MSG_RESULT([skip at user request]) + fi + else + AC_MSG_RESULT([yes]) + fi + + # + # if the macro parameter ``version'' is set, honour it + # + if test -n "$1"; then + AC_MSG_CHECKING([for a version of Python $1]) + ac_supports_python_ver=`$PYTHON -c "import sys, string; \ + ver = string.split(sys.version)[[0]]; \ + print ver $1"` + if test "$ac_supports_python_ver" = "True"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([this package requires Python $1. +If you have it installed, but it isn't the default Python +interpreter in your system path, please pass the PYTHON_VERSION +variable to configure. See ``configure --help'' for reference. +]) + PYTHON_VERSION="" + fi + fi + + # + # Check if you have distutils, else fail + # + AC_MSG_CHECKING([for the distutils Python package]) + ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` + if test -z "$ac_distutils_result"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot import Python module "distutils". +Please check your Python installation. The error was: +$ac_distutils_result]) + PYTHON_VERSION="" + fi + + # + # Check for Python include path + # + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON_CPPFLAGS"; then + python_path=`$PYTHON -c "import distutils.sysconfig; \ + print distutils.sysconfig.get_python_inc();"` + if test -n "${python_path}"; then + python_path="-I$python_path" + fi + PYTHON_CPPFLAGS=$python_path + fi + AC_MSG_RESULT([$PYTHON_CPPFLAGS]) + AC_SUBST([PYTHON_CPPFLAGS]) + + # + # Check for Python library path + # + AC_MSG_CHECKING([for Python library path]) + if test -z "$PYTHON_LDFLAGS"; then + # (makes two attempts to ensure we've got a version number + # from the interpreter) + py_version=`$PYTHON -c "from distutils.sysconfig import *; \ + from string import join; \ + print join(get_config_vars('VERSION'))"` + if test "$py_version" == "[None]"; then + if test -n "$PYTHON_VERSION"; then + py_version=$PYTHON_VERSION + else + py_version=`$PYTHON -c "import sys; \ + print sys.version[[:3]]"` + fi + fi + + PYTHON_LDFLAGS=`$PYTHON -c "from distutils.sysconfig import *; \ + from string import join; \ + print '-L' + get_python_lib(0,1), \ + '-lpython';"`$py_version + fi + AC_MSG_RESULT([$PYTHON_LDFLAGS]) + AC_SUBST([PYTHON_LDFLAGS]) + + # + # Check for site packages + # + AC_MSG_CHECKING([for Python site-packages path]) + if test -z "$PYTHON_SITE_PKG"; then + PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \ + print distutils.sysconfig.get_python_lib(0,0);"` + fi + AC_MSG_RESULT([$PYTHON_SITE_PKG]) + AC_SUBST([PYTHON_SITE_PKG]) + + # + # libraries which must be linked in when embedding + # + AC_MSG_CHECKING(python extra libraries) + if test -z "$PYTHON_EXTRA_LIBS"; then + PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print conf('LOCALMODLIBS'), conf('LIBS')"` + fi + AC_MSG_RESULT([$PYTHON_EXTRA_LIBS]) + AC_SUBST(PYTHON_EXTRA_LIBS) + + # + # linking flags needed when embedding + # + AC_MSG_CHECKING(python extra linking flags) + if test -z "$PYTHON_EXTRA_LDFLAGS"; then + PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print conf('LINKFORSHARED')"` + fi + AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS]) + AC_SUBST(PYTHON_EXTRA_LDFLAGS) + + # + # final check to see if everything compiles alright + # + AC_MSG_CHECKING([consistency of all components of python development environment]) + AC_LANG_PUSH([C]) + # save current global flags + LIBS="$ac_save_LIBS $PYTHON_LDFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" + AC_TRY_LINK([ + #include + ],[ + Py_Initialize(); + ],[pythonexists=yes],[pythonexists=no]) + + AC_MSG_RESULT([$pythonexists]) + + if test ! "$pythonexists" = "yes"; then + AC_MSG_ERROR([ + Could not link test program to Python. Maybe the main Python library has been + installed in some non-standard library path. If so, pass it to configure, + via the LDFLAGS environment variable. + Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib" + ============================================================================ + ERROR! + You probably have to install the development version of the Python package + for your distribution. The exact name of this package varies among them. + ============================================================================ + ]) + PYTHON_VERSION="" + fi + AC_LANG_POP + # turn back to default flags + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + + # + # all done! + # +]) diff --git a/m4/swig_python.m4 b/m4/swig_python.m4 new file mode 100644 index 0000000..2496976 --- /dev/null +++ b/m4/swig_python.m4 @@ -0,0 +1,65 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/swig_python.html +# =========================================================================== +# +# SYNOPSIS +# +# SWIG_PYTHON([use-shadow-classes = {no, yes}]) +# +# DESCRIPTION +# +# Checks for Python and provides the $(SWIG_PYTHON_CPPFLAGS), and +# $(SWIG_PYTHON_OPT) output variables. +# +# $(SWIG_PYTHON_OPT) contains all necessary SWIG options to generate code +# for Python. Shadow classes are enabled unless the value of the optional +# first argument is exactly 'no'. If you need multi module support +# (provided by the SWIG_MULTI_MODULE_SUPPORT macro) use +# $(SWIG_PYTHON_LIBS) to link against the appropriate library. It contains +# the SWIG Python runtime library that is needed by the type check system +# for example. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Sebastian Huber +# Copyright (c) 2008 Alan W. Irwin +# Copyright (c) 2008 Rafael Laboissiere +# Copyright (c) 2008 Andrew Collier +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([SWIG_PYTHON],[ + AC_REQUIRE([AC_PROG_SWIG]) + AC_REQUIRE([AC_PYTHON_DEVEL]) + test "x$1" != "xno" || swig_shadow=" -noproxy" + AC_SUBST([SWIG_PYTHON_OPT],[-python$swig_shadow]) + AC_SUBST([SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS]) +]) diff --git a/src/MobileSync.c b/src/MobileSync.c index ae22f4b..a2a361e 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -115,11 +115,11 @@ static void iphone_msync_stop_session(iphone_msync_client_t client) array = NULL; } -void iphone_msync_free_client(iphone_msync_client_t client) +iphone_error_t iphone_msync_free_client(iphone_msync_client_t client) { iphone_msync_stop_session(client); - iphone_mux_free_client(client->connection); + return iphone_mux_free_client(client->connection); } /** Polls the iPhone for MobileSync data. diff --git a/src/MobileSync.h b/src/MobileSync.h index b59547c..7655b59 100644 --- a/src/MobileSync.h +++ b/src/MobileSync.h @@ -27,19 +27,12 @@ #include -struct iphone_msync_client_int; -typedef struct iphone_msync_client_int *iphone_msync_client_t; + struct iphone_msync_client_int { iphone_umux_client_t connection; }; -iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int dst_port, - iphone_msync_client_t * client); -void iphone_msync_free_client(iphone_msync_client_t client); - -iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist); -iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist); iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client); diff --git a/swig/Makefile.am b/swig/Makefile.am new file mode 100644 index 0000000..e47356b --- /dev/null +++ b/swig/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/include $(libplist_CFLAGS) + +BUILT_SOURCES = $(srcdir)/iphone_wrap.c +SWIG_SOURCES = iphone.i + +swigincludedir =$(includedir)/libiphone/swig +swiginclude_HEADERS = $(SWIG_SOURCES) + +pkgpython_PYTHON = iPhone.py __init__.py +pkgpyexec_LTLIBRARIES = _iPhone.la +_iPhone_la_SOURCES = $(srcdir)/iphone_wrap.c $(SWIG_SOURCES) +_iPhone_la_CFLAGS = $(PYTHON_CPPFLAGS) -I$(top_srcdir)/src +_iPhone_la_LDFLAGS = -module $(PYTHON_LDFLAGS) +_iPhone_la_LIBADD = ../src/libiphone.la + +$(srcdir)/iphone_wrap.c : $(SWIG_SOURCES) + $(SWIG) $(SWIG_PYTHON_OPT) $(INCLUDES) -I$(top_srcdir)/src -o $@ $< + diff --git a/swig/__init__.py b/swig/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/swig/__init__.py @@ -0,0 +1 @@ + diff --git a/swig/iphone.i b/swig/iphone.i new file mode 100644 index 0000000..fb16208 --- /dev/null +++ b/swig/iphone.i @@ -0,0 +1,123 @@ + /* swig.i */ + %module(package="libiphone") iPhone + %{ + /* Includes the header in the wrapper code */ + #include + #include + + typedef struct { + iphone_device_t dev; + } iPhone; + + typedef struct { + iphone_device_t dev; + iphone_lckd_client_t client; + } Lockdownd; + + typedef struct { + iphone_msync_client_t client; + } MobileSync; +//typedef struct { +// plist_t node; +//} PListNode; + %} +/* Parse the header file to generate wrappers */ +%include "plist/swig/plist.i" + //(module="libplist.PList")override module name until package path gets fixed in swig (1.3.37) + +typedef struct { + iphone_device_t dev; +} iPhone; + +typedef struct { + iphone_device_t dev; + iphone_lckd_client_t client; +} Lockdownd; + +typedef struct { + iphone_msync_client_t client; +} MobileSync; + +%extend iPhone { // Attach these functions to struct iPhone + iPhone() { + iPhone* phone = (iPhone*) malloc(sizeof(iPhone)); + if (IPHONE_E_SUCCESS == iphone_get_device ( &phone->dev )) + return phone; + free(phone); + return NULL; + } + + ~iPhone() { + iphone_free_device ( $self->dev ); + free($self); + } + + Lockdownd* GetLockdownClient() { + Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); + client->client = NULL; + if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( $self->dev , &(client->client)) ) { + client->dev = $self->dev; + return client; + } + free(client); + return NULL; + } +}; + +%extend Lockdownd { // Attach these functions to struct Lockdownd + Lockdownd(iPhone* phone) { + if (!phone) return NULL; + Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); + client->client = NULL; + if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( phone->dev , &client->client)) { + client->dev = phone->dev; + return client; + } + else { + free(client); + return NULL; + } + } + + ~Lockdownd() { + iphone_lckd_free_client ( $self->client ); + free($self); + } + + MobileSync* GetMobileSyncClient() { + int port = 0; + if (IPHONE_E_SUCCESS == iphone_lckd_start_service ( $self->client, "com.apple.mobilesync", &port )) { + MobileSync* client = (MobileSync*) malloc(sizeof(MobileSync)); + client->client = NULL; + if (IPHONE_E_SUCCESS == iphone_msync_new_client ( $self->dev, 3432, port, &(client->client))) + return client; + } + return NULL; + } +}; + +%extend MobileSync { // Attach these functions to struct MobileSync + MobileSync(iPhone* phone, int src_port, int dst_port) { + if (!phone) return NULL; + MobileSync* client = (MobileSync*) malloc(sizeof(MobileSync)); + client->client = NULL; + iphone_msync_new_client ( phone->dev, src_port, dst_port, &client->client); + return client; + } + + ~MobileSync() { + iphone_msync_free_client ( $self->client ); + free($self); + } + + void Send(PListNode* node) { + iphone_msync_send($self->client, node->node); + } + + PListNode* Receive() { + PListNode* node = NULL; + iphone_msync_recv($self->client, &(node->node)); + return node; + } +}; + -- cgit v1.1-32-gdbae From 47347ff723dd3c03b0006c150b02abaa2b9f4a76 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Tue, 13 Jan 2009 22:56:35 +0100 Subject: Fix some bugs in interface (Receive() still doesn't work). --- dev/msync.py | 40 ++++++++++++++++++++++++++++++++++++++++ swig/iphone.i | 28 ++++++++++++++++------------ 2 files changed, 56 insertions(+), 12 deletions(-) create mode 100755 dev/msync.py diff --git a/dev/msync.py b/dev/msync.py new file mode 100755 index 0000000..4170f87 --- /dev/null +++ b/dev/msync.py @@ -0,0 +1,40 @@ +#! /usr/bin/env python + +from libiphone.iPhone import * + +# get msync client +def GetMobileSyncClient() : + phone = iPhone() + if not phone.InitDevice() : + print "Couldn't find device, is it connected ?\n" + return None + lckd = phone.GetLockdownClient() + if not lckd : + print "Failed to start lockdown service.\n" + return None + msync = lckd.GetMobileSyncClient() + if not msync : + print "Failed to start mobilesync service.\n" + return None + return msync + + +msync = GetMobileSyncClient() + +if not msync : + exit(1) + +array = PListNode(PLIST_ARRAY) +array.AddSubString("SDMessageSyncDataClassWithDevice") +array.AddSubString("com.apple.Contacts"); +array.AddSubString("---"); +array.AddSubString("2009-01-13 22:25:58 +0100"); +array.AddSubUInt(106); +array.AddSubString("___EmptyParameterString___"); + +msync.Send(array) +array = msync.Receive() +print array.ToXml() + + + diff --git a/swig/iphone.i b/swig/iphone.i index fb16208..a0fe340 100644 --- a/swig/iphone.i +++ b/swig/iphone.i @@ -4,7 +4,7 @@ /* Includes the header in the wrapper code */ #include #include - +#include "../src/utils.h" typedef struct { iphone_device_t dev; } iPhone; @@ -17,13 +17,10 @@ typedef struct { iphone_msync_client_t client; } MobileSync; -//typedef struct { -// plist_t node; -//} PListNode; %} /* Parse the header file to generate wrappers */ +%include "stdint.i" %include "plist/swig/plist.i" - //(module="libplist.PList")override module name until package path gets fixed in swig (1.3.37) typedef struct { iphone_device_t dev; @@ -41,10 +38,9 @@ typedef struct { %extend iPhone { // Attach these functions to struct iPhone iPhone() { iPhone* phone = (iPhone*) malloc(sizeof(iPhone)); - if (IPHONE_E_SUCCESS == iphone_get_device ( &phone->dev )) - return phone; - free(phone); - return NULL; + phone->dev = NULL; + iphone_set_debug_mask(DBGMASK_LOCKDOWND | DBGMASK_MOBILESYNC); + return phone; } ~iPhone() { @@ -52,9 +48,16 @@ typedef struct { free($self); } + int InitDevice() { + if (IPHONE_E_SUCCESS == iphone_get_device ( &($self->dev))) + return 1; + return 0; + } + Lockdownd* GetLockdownClient() { Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); client->client = NULL; + client->dev = NULL; if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( $self->dev , &(client->client)) ) { client->dev = $self->dev; return client; @@ -69,7 +72,7 @@ typedef struct { if (!phone) return NULL; Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); client->client = NULL; - if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( phone->dev , &client->client)) { + if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( phone->dev , &(client->client))) { client->dev = phone->dev; return client; } @@ -101,7 +104,7 @@ typedef struct { if (!phone) return NULL; MobileSync* client = (MobileSync*) malloc(sizeof(MobileSync)); client->client = NULL; - iphone_msync_new_client ( phone->dev, src_port, dst_port, &client->client); + iphone_msync_new_client ( phone->dev, src_port, dst_port, &(client->client)); return client; } @@ -115,7 +118,8 @@ typedef struct { } PListNode* Receive() { - PListNode* node = NULL; + PListNode* node = (PListNode*)malloc(sizeof(PListNode)); + node->node = NULL; iphone_msync_recv($self->client, &(node->node)); return node; } -- cgit v1.1-32-gdbae From 7f2e0f5f719a7092b45b0b7d538137a9b7d78567 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 15 Jan 2009 18:13:55 +0100 Subject: Rework SWIG interface to not duplicate constructor and destructor code. --- swig/iphone.i | 109 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 40 deletions(-) diff --git a/swig/iphone.i b/swig/iphone.i index a0fe340..e970e89 100644 --- a/swig/iphone.i +++ b/swig/iphone.i @@ -10,13 +10,21 @@ } iPhone; typedef struct { - iphone_device_t dev; + iPhone* dev; iphone_lckd_client_t client; } Lockdownd; typedef struct { + Lockdownd* lckd; iphone_msync_client_t client; } MobileSync; + +//now declare funtions to handle creation and deletion of objects +void my_delete_iPhone(iPhone* dev); +Lockdownd* my_new_Lockdownd(iPhone* phone); +void my_delete_Lockdownd(Lockdownd* lckd); +MobileSync* my_new_MobileSync(Lockdownd* lckd); + %} /* Parse the header file to generate wrappers */ %include "stdint.i" @@ -27,14 +35,64 @@ typedef struct { } iPhone; typedef struct { - iphone_device_t dev; + iPhone* dev; iphone_lckd_client_t client; } Lockdownd; typedef struct { + Lockdownd* lckd; iphone_msync_client_t client; } MobileSync; +%inline %{ +//now define funtions to handle creation and deletion of objects + + +void my_delete_iPhone(iPhone* dev) { + if (dev) { + iphone_free_device ( dev->dev ); + free(dev); + } +} + +Lockdownd* my_new_Lockdownd(iPhone* phone) { + if (!phone) return NULL; + Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); + client->dev = phone; + client->client = NULL; + if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( phone->dev , &(client->client))) { + return client; + } + else { + free(client); + return NULL; + } +} + +void my_delete_Lockdownd(Lockdownd* lckd) { + if (lckd) { + my_delete_iPhone(lckd->dev); + iphone_lckd_free_client ( lckd->client ); + free(lckd); + } +} + +MobileSync* my_new_MobileSync(Lockdownd* lckd) { + if (!lckd || !lckd->dev) return NULL; + MobileSync* client = NULL; + int port = 0; + if (IPHONE_E_SUCCESS == iphone_lckd_start_service ( lckd->client, "com.apple.mobilesync", &port )) { + client = (MobileSync*) malloc(sizeof(MobileSync)); + client->lckd = lckd; + client->client = NULL; + iphone_msync_new_client ( lckd->dev->dev, 3432, port, &(client->client)); + } + return client; +} + +%} + + %extend iPhone { // Attach these functions to struct iPhone iPhone() { iPhone* phone = (iPhone*) malloc(sizeof(iPhone)); @@ -44,8 +102,7 @@ typedef struct { } ~iPhone() { - iphone_free_device ( $self->dev ); - free($self); + my_delete_iPhone($self); } int InitDevice() { @@ -55,60 +112,32 @@ typedef struct { } Lockdownd* GetLockdownClient() { - Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); - client->client = NULL; - client->dev = NULL; - if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( $self->dev , &(client->client)) ) { - client->dev = $self->dev; - return client; - } - free(client); - return NULL; + return my_new_Lockdownd($self); } }; + %extend Lockdownd { // Attach these functions to struct Lockdownd Lockdownd(iPhone* phone) { - if (!phone) return NULL; - Lockdownd* client = (Lockdownd*) malloc(sizeof(Lockdownd)); - client->client = NULL; - if (IPHONE_E_SUCCESS == iphone_lckd_new_client ( phone->dev , &(client->client))) { - client->dev = phone->dev; - return client; - } - else { - free(client); - return NULL; - } + return my_new_Lockdownd(phone); } ~Lockdownd() { - iphone_lckd_free_client ( $self->client ); - free($self); + my_delete_Lockdownd($self); } MobileSync* GetMobileSyncClient() { - int port = 0; - if (IPHONE_E_SUCCESS == iphone_lckd_start_service ( $self->client, "com.apple.mobilesync", &port )) { - MobileSync* client = (MobileSync*) malloc(sizeof(MobileSync)); - client->client = NULL; - if (IPHONE_E_SUCCESS == iphone_msync_new_client ( $self->dev, 3432, port, &(client->client))) - return client; - } - return NULL; + return my_new_MobileSync($self); } }; %extend MobileSync { // Attach these functions to struct MobileSync - MobileSync(iPhone* phone, int src_port, int dst_port) { - if (!phone) return NULL; - MobileSync* client = (MobileSync*) malloc(sizeof(MobileSync)); - client->client = NULL; - iphone_msync_new_client ( phone->dev, src_port, dst_port, &(client->client)); - return client; + MobileSync(Lockdownd* lckd) { + return my_new_MobileSync(lckd); } ~MobileSync() { + my_delete_Lockdownd($self->lckd); iphone_msync_free_client ( $self->client ); free($self); } -- cgit v1.1-32-gdbae From 0934d1ac021dfb7907e4b580b38aa4a938cf2180 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 22 Jan 2009 22:21:12 +0100 Subject: Move things around and clean up some code. --- dev/msyncclient.c | 2 -- include/libiphone/libiphone.h | 11 ++++++++++- src/MobileSync.c | 8 +++++--- src/usbmux.c | 1 + src/utils.h | 6 ------ 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/dev/msyncclient.c b/dev/msyncclient.c index a6764b4..2762f04 100644 --- a/dev/msyncclient.c +++ b/dev/msyncclient.c @@ -28,8 +28,6 @@ #include #include -#include "../src/MobileSync.h" -#include "../src/utils.h" int main(int argc, char *argv[]) diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index 59d2de2..6197923 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -81,8 +81,17 @@ typedef struct iphone_afc_file_int *iphone_afc_file_t; struct iphone_msync_client_int; typedef struct iphone_msync_client_int *iphone_msync_client_t; -//device related functions +//debug related functions +#define DBGMASK_ALL 0xFFFF +#define DBGMASK_NONE 0x0000 +#define DBGMASK_USBMUX (1 << 1) +#define DBGMASK_LOCKDOWND (1 << 2) +#define DBGMASK_MOBILESYNC (1 << 3) + +void iphone_set_debug_mask(uint16_t mask); void iphone_set_debug(int level); + +//device related functions iphone_error_t iphone_get_device ( iphone_device_t *device ); iphone_error_t iphone_free_device ( iphone_device_t device ); diff --git a/src/MobileSync.c b/src/MobileSync.c index a2a361e..752aee9 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -51,7 +51,7 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int ret = iphone_msync_recv(client_loc, &array); plist_t msg_node = - plist_find_node(array, PLIST_STRING, "DLMessageVersionExchange", strlen("DLMessageVersionExchange")); + plist_find_node_by_string(array, "DLMessageVersionExchange"); plist_t ver_1 = plist_get_next_sibling(msg_node); plist_t ver_2 = plist_get_next_sibling(ver_1); @@ -83,7 +83,7 @@ iphone_error_t iphone_msync_new_client(iphone_device_t device, int src_port, int ret = iphone_msync_recv(client_loc, &array); plist_t rep_node = - plist_find_node(array, PLIST_STRING, "DLMessageDeviceReady", strlen("DLMessageDeviceReady")); + plist_find_node_by_string(array, "DLMessageDeviceReady"); if (rep_node) { ret = IPHONE_E_SUCCESS; @@ -117,8 +117,10 @@ static void iphone_msync_stop_session(iphone_msync_client_t client) iphone_error_t iphone_msync_free_client(iphone_msync_client_t client) { - iphone_msync_stop_session(client); + if (!client) + return IPHONE_E_INVALID_ARG; + iphone_msync_stop_session(client); return iphone_mux_free_client(client->connection); } diff --git a/src/usbmux.c b/src/usbmux.c index eb7ec97..5eaa1d1 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -313,6 +313,7 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t } else { memcpy(data, client->recv_buffer, client->r_len); free(client->recv_buffer); // don't need to deal with anymore, but... + client->recv_buffer = NULL; offset = client->r_len; // see #2b, above client->r_len = 0; } diff --git a/src/utils.h b/src/utils.h index d9a441d..1750b8e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,13 +24,7 @@ #include "libiphone/libiphone.h" -#define DBGMASK_ALL 0xFFFF -#define DBGMASK_NONE 0x0000 -#define DBGMASK_USBMUX (1 << 1) -#define DBGMASK_LOCKDOWND (1 << 2) -#define DBGMASK_MOBILESYNC (1 << 3) -void iphone_set_debug_mask(uint16_t mask); inline void log_debug_msg(const char *format, ...); inline void log_dbg_msg(uint16_t id, const char *format, ...); -- cgit v1.1-32-gdbae From 185294a0f9a689a231d3d0d8cde1864d4b0bdaa0 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 29 Jan 2009 18:35:38 +0100 Subject: Add more warning flags and remove useless libxml2 dependency. --- configure.ac | 4 +++- dev/Makefile.am | 4 ++-- m4/as-compiler-flag.m4 | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 4 ++-- 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 m4/as-compiler-flag.m4 diff --git a/configure.ac b/configure.ac index 87ed8dc..71bab50 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,6 @@ AC_PROG_CC 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) @@ -66,4 +65,7 @@ if test "$no_debug_code" = true; then AC_DEFINE(STRIP_DEBUG_CODE,1,[Strip debug reporting code]) fi +AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") +AC_SUBST(GLOBAL_CFLAGS) + AC_OUTPUT(Makefile src/Makefile include/Makefile fdi/Makefile dev/Makefile swig/Makefile libiphone-1.0.pc) diff --git a/dev/Makefile.am b/dev/Makefile.am index 7ca7e99..f976ccc 100644 --- a/dev/Makefile.am +++ b/dev/Makefile.am @@ -1,7 +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 = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) -g +AM_LDFLAGS = $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) bin_PROGRAMS = iphoneclient lckd-client afccheck msyncclient diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4 new file mode 100644 index 0000000..0f660cf --- /dev/null +++ b/m4/as-compiler-flag.m4 @@ -0,0 +1,62 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef + +dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + m4_ifvaln([$2],[$2]) + true + else + m4_ifvaln([$3],[$3]) + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +dnl AS_COMPILER_FLAGS(VAR, FLAGS) +dnl Tries to compile with the given CFLAGS. + +AC_DEFUN([AS_COMPILER_FLAGS], +[ + list=$2 + flags_supported="" + flags_unsupported="" + AC_MSG_CHECKING([for supported compiler flags]) + for each in $list + do + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $each" + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + flags_supported="$flags_supported $each" + else + flags_unsupported="$flags_unsupported $each" + fi + done + AC_MSG_RESULT([$flags_supported]) + if test "X$flags_unsupported" != X ; then + AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) + fi + $1="$$1 $flags_supported" +]) + diff --git a/src/Makefile.am b/src/Makefile.am index 1b97f45..039632f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I$(top_srcdir)/include -AM_CFLAGS = $(libxml2_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) -g -Wall -AM_LDFLAGS = $(libxml2_LIBS) $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_LIBS) +AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) -g +AM_LDFLAGS = $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_LIBS) bin_PROGRAMS = libiphone-initconf -- cgit v1.1-32-gdbae From c00d8d76c04273f796c3d992300068dd21c7bd3e Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 29 Jan 2009 18:47:46 +0100 Subject: Completly remove libxml dependency and change libplist-1.0 dependency to libplist. --- configure.ac | 2 +- dev/main.c | 3 --- dev/msyncclient.c | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 71bab50..ec7e11a 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ 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) -PKG_CHECK_MODULES(libplist, libplist-1.0 >= 0.1.0) +PKG_CHECK_MODULES(libplist, libplist >= 0.1.0) # Checks for header files. AC_HEADER_STDC diff --git a/dev/main.c b/dev/main.c index f865e52..6514bf8 100644 --- a/dev/main.c +++ b/dev/main.c @@ -24,9 +24,6 @@ #include #include -#include -#include - #include #include "../src/utils.h" diff --git a/dev/msyncclient.c b/dev/msyncclient.c index 2762f04..804e1ed 100644 --- a/dev/msyncclient.c +++ b/dev/msyncclient.c @@ -24,9 +24,6 @@ #include #include -#include -#include - #include -- cgit v1.1-32-gdbae From 0d05f8de79ee91e9be80c6296eff9ce216582ba4 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Thu, 29 Jan 2009 22:30:16 +0100 Subject: Update to latest libplist API. --- src/MobileSync.c | 13 +++++-------- src/lockdown.c | 18 +++++++++--------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/MobileSync.c b/src/MobileSync.c index 752aee9..839ed2b 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -222,7 +222,7 @@ iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client) ret = iphone_msync_recv(client, &array); - plist_t rep_node = plist_find_node(array, PLIST_STRING, "SDSyncTypeSlow", strlen("SDSyncTypeSlow")); + plist_t rep_node = plist_find_node_by_string(array, "SDSyncTypeSlow"); if (!rep_node) return ret; @@ -244,10 +244,9 @@ iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client) plist_t contact_node; plist_t switch_node; - contact_node = plist_find_node(array, PLIST_STRING, "com.apple.Contacts", strlen("com.apple.Contacts")); + contact_node = plist_find_node_by_string(array, "com.apple.Contacts"); switch_node = - plist_find_node(array, PLIST_STRING, "SDMessageDeviceReadyToReceiveChanges", - strlen("SDMessageDeviceReadyToReceiveChanges")); + plist_find_node_by_string(array, "SDMessageDeviceReadyToReceiveChanges"); while (NULL == switch_node) { @@ -264,10 +263,8 @@ iphone_error_t iphone_msync_get_all_contacts(iphone_msync_client_t client) ret = iphone_msync_recv(client, &array); - contact_node = plist_find_node(array, PLIST_STRING, "com.apple.Contacts", strlen("com.apple.Contacts")); - switch_node = - plist_find_node(array, PLIST_STRING, "SDMessageDeviceReadyToReceiveChanges", - strlen("SDMessageDeviceReadyToReceiveChanges")); + contact_node = plist_find_node_by_string(array, "com.apple.Contacts"); + switch_node = plist_find_node_by_string(array, "SDMessageDeviceReadyToReceiveChanges"); } array = plist_new_array(); diff --git a/src/lockdown.c b/src/lockdown.c index a02e6a8..2f48dfd 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -411,15 +411,15 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c if (!strcmp(result_key, "Value")) { log_dbg_msg(DBGMASK_LOCKDOWND, "lockdownd_generic_get_value(): success\n"); - plist_type value_value_type; - char *value_value = NULL; - uint64_t valval_length = 0; + plist_type value_value_type = plist_get_node_type(value_value_node); + if (PLIST_STRING == value_value_type) { + char *value_value = NULL; + plist_get_string_val(value_value_node, &value_value); - plist_get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value), &valval_length); - - value->data = value_value; - value->size = valval_length; - ret = IPHONE_E_SUCCESS; + value->data = value_value; + value->size = strlen(value_value); + ret = IPHONE_E_SUCCESS; + } } free(result_key); } @@ -825,7 +825,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c if (!dict) return IPHONE_E_PLIST_ERROR; - plist_t query_node = plist_find_node(dict, PLIST_STRING, "StartSession", strlen("StartSession")); + plist_t query_node = plist_find_node_by_string(dict, "StartSession"); plist_t result_key_node = plist_get_next_sibling(query_node); plist_t result_value_node = plist_get_next_sibling(result_key_node); -- cgit v1.1-32-gdbae From f893e8a9e2cc197522f838b3f2bbec8862953c2f Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Sun, 12 Apr 2009 16:08:06 +0200 Subject: Use less secure random number generation so we can generate private keys on the fly. Drop libiphone-initconf. --- README | 22 +--- configure.ac | 4 +- src/Makefile.am | 8 -- src/initconf.c | 213 ------------------------------------- src/lockdown.c | 160 +++++++++++++++------------- src/lockdown.h | 8 +- src/userpref.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++---------- src/userpref.h | 50 ++------- 8 files changed, 373 insertions(+), 416 deletions(-) delete mode 100644 src/initconf.c diff --git a/README b/README index 5bc5c5e..955da4e 100644 --- a/README +++ b/README @@ -7,10 +7,11 @@ For: You must have: libgnutls-dev + libgcrypt-dev libusb-dev libfuse-dev (and the associated kernel modules) libglib2.0-dev - libxml2-dev + libplist-dev make autoheader automake @@ -22,31 +23,12 @@ 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. - == Who/what/where? == wiki: diff --git a/configure.ac b/configure.ac index 29f9be3..e2f98c7 100644 --- a/configure.ac +++ b/configure.ac @@ -25,11 +25,11 @@ 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) -PKG_CHECK_MODULES(libplist, libplist >= 0.1.0) +PKG_CHECK_MODULES(libplist, libplist >= 0.10) # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h]) +AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h gcrypt.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/src/Makefile.am b/src/Makefile.am index 71667ae..a10254c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,13 +3,5 @@ INCLUDES = -I$(top_srcdir)/include AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) AM_LDFLAGS = $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_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 lockdown.c AFC.c NotificationProxy.c userpref.c utils.c MobileSync.c diff --git a/src/initconf.c b/src/initconf.c deleted file mode 100644 index 538f344..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. - */ -static 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. - */ -static 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/lockdown.c b/src/lockdown.c index 63f9090..e720b29 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -1,22 +1,22 @@ /* * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "usbmux.h" @@ -67,7 +67,7 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone) /** * Closes the lockdownd communication session, by sending - * the StopSession Request to the device. + * the StopSession Request to the device. * * @param control The lockdown client */ @@ -128,7 +128,7 @@ static void iphone_lckd_stop_session(iphone_lckd_client_t control) /** * Shuts down the SSL session by first calling iphone_lckd_stop_session - * to cleanly close the lockdownd communication session, and then + * to cleanly close the lockdownd communication session, and then * performing a close notify, which is done by "gnutls_bye". * * @param client The lockdown client @@ -219,6 +219,7 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, plist_t * plist) return IPHONE_E_NOT_ENOUGH_DATA; } + log_dbg_msg(DBGMASK_LOCKDOWND, "Recv msg :\nsize : %i\nbuffer :\n%s\n", bytes, receive); plist_from_xml(receive, bytes, plist); free(receive); @@ -229,7 +230,7 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, plist_t * plist) } /** 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. * @@ -272,7 +273,7 @@ iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, plist_t plist) } /** 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 @@ -338,7 +339,7 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control) * * @return IPHONE_E_SUCCESS on success. */ -iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, char *req_string, +iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, const char *req_string, gnutls_datum_t * value) { if (!control || !req_key || !value || value->data) @@ -396,7 +397,7 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c return ret; } - plist_t value_key_node = plist_get_next_sibling(result_key_node); + plist_t value_key_node = plist_find_node_by_key(dict, "Value");//plist_get_next_sibling(result_value_node); plist_t value_value_node = plist_get_next_sibling(value_key_node); plist_type value_key_type = plist_get_node_type(value_key_node); @@ -418,6 +419,16 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c value->size = strlen(value_value); ret = IPHONE_E_SUCCESS; } + + if (PLIST_DATA == value_value_type) { + char *value_value = NULL; + uint64_t size = 0; + plist_get_data_val(value_value_node, &value_value, &size); + + value->data = value_value; + value->size = size; + ret = IPHONE_E_SUCCESS; + } } free(result_key); } @@ -435,8 +446,9 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c 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); + iphone_error_t ret = lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", &temp); *uid = temp.data; + return ret; } /** Askes for the device's public key. Part of the lockdownd handshake. @@ -480,6 +492,7 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client if (IPHONE_E_SUCCESS != ret) { log_debug_msg("Device refused to send uid.\n"); } + log_debug_msg("Device uid: %s\n", uid); host_id = get_host_id(); if (IPHONE_E_SUCCESS == ret && !host_id) { @@ -495,19 +508,22 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client uid = NULL; } - ret = lockdownd_start_SSL_session(client_loc, host_id); - if (IPHONE_E_SUCCESS != ret) { - ret = IPHONE_E_SSL_ERROR; - log_debug_msg("SSL Session opening failed.\n"); - } + if (IPHONE_E_SUCCESS == ret) { + ret = lockdownd_start_SSL_session(client_loc, host_id); + if (IPHONE_E_SUCCESS != ret) { + ret = IPHONE_E_SSL_ERROR; + log_debug_msg("SSL Session opening failed.\n"); + } - if (host_id) { - free(host_id); - host_id = NULL; + if (host_id) { + free(host_id); + host_id = NULL; + } + + if (IPHONE_E_SUCCESS == ret) + *client = client_loc; } - if (IPHONE_E_SUCCESS == ret) - *client = client_loc; return ret; } @@ -534,6 +550,7 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch log_debug_msg("Device refused to send public key.\n"); return ret; } + log_debug_msg("device public key :\n %s.\n", public_key.data); ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); if (ret != IPHONE_E_SUCCESS) { @@ -547,15 +564,15 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch dict_record = plist_new_dict(); plist_add_sub_node(dict, dict_record); plist_add_sub_key_el(dict_record, "DeviceCertificate"); - plist_add_sub_data_el(dict_record, device_cert.data, device_cert.size); + plist_add_sub_data_el(dict_record, (const char*)device_cert.data, device_cert.size); plist_add_sub_key_el(dict_record, "HostCertificate"); - plist_add_sub_data_el(dict_record, host_cert.data, host_cert.size); + plist_add_sub_data_el(dict_record, (const char*)host_cert.data, host_cert.size); plist_add_sub_key_el(dict_record, "HostID"); plist_add_sub_string_el(dict_record, host_id); plist_add_sub_key_el(dict_record, "RootCertificate"); - plist_add_sub_data_el(dict_record, root_cert.data, root_cert.size); - plist_add_sub_key_el(dict_record, "Request"); - plist_add_sub_string_el(dict_record, "Pair"); + plist_add_sub_data_el(dict_record, (const char*)root_cert.data, root_cert.size); + plist_add_sub_key_el(dict, "Request"); + plist_add_sub_string_el(dict, "Pair"); /* send to iPhone */ ret = iphone_lckd_send(control, dict); @@ -667,7 +684,7 @@ void lockdownd_close(iphone_lckd_client_t control) /** 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, @@ -718,7 +735,7 @@ iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t gnutls_global_init(); gnutls_datum_t essentially_null = { strdup("abababababababab"), strlen("abababababababab") }; - gnutls_x509_privkey_t fake_privkey, root_privkey; + gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey; gnutls_x509_crt_t dev_cert, root_cert, host_cert; gnutls_x509_privkey_init(&fake_privkey); @@ -731,57 +748,50 @@ iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t &essentially_null, &essentially_null)) { gnutls_x509_privkey_init(&root_privkey); + gnutls_x509_privkey_init(&host_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); + ret = get_keys_and_certs( root_privkey, root_cert, host_privkey, host_cert); 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; + + /* 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); + + gnutls_datum_t pem_root_cert = { NULL, 0 }; + gnutls_datum_t pem_host_cert = { NULL, 0 }; + + if ( IPHONE_E_SUCCESS == get_certs_as_pem(&pem_root_cert, &pem_host_cert) ) { + /* 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; + + g_free(pem_root_cert.data); + g_free(pem_host_cert.data); + } + } } - gnutls_free(pem_root_priv.data); - gnutls_free(pem_root_cert.data); - gnutls_free(pem_host_cert.data); } } diff --git a/src/lockdown.h b/src/lockdown.h index cad06a3..7485006 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -8,15 +8,15 @@ * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LOCKDOWND_H @@ -41,7 +41,7 @@ struct iphone_lckd_client_int { 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, const char *req_key, char *req_string, +iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, const char *req_string, gnutls_datum_t * value); iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key); diff --git a/src/userpref.c b/src/userpref.c index 3e5eb06..0e83133 100644 --- a/src/userpref.c +++ b/src/userpref.c @@ -8,25 +8,28 @@ * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include +#include #include +#include +#include +#include + #include "userpref.h" #include "utils.h" -#include -#include #define LIBIPHONE_CONF_DIR "libiphone" #define LIBIPHONE_CONF_FILE "libiphonerc" @@ -49,9 +52,75 @@ static void create_config_dir(void) g_free(config_dir); } +static int get_rand(int min, int max) +{ + int retval = (rand() % (max - min)) + min; + return retval; +} + +/** Generates a valid HostID (which is actually a UUID). + * + * @return A null terminated string containing a valid HostID. + */ +static 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; +} + +/** Store HostID in config file. + * + * @param host_id A null terminated string containing a valid HostID. + */ +static int write_host_id(char *host_id) +{ + GKeyFile *key_file; + gsize length; + gchar *buf, *config_file; + GIOChannel *file; + + if (!host_id) + return 0; + + /* Make sure config directory exists */ + create_config_dir(); + + /* Now parse file to get the HostID */ + key_file = g_key_file_new(); -/** Reads the HostID from a previously generated configuration file. - * + /* 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); + return 1; +} + +/** 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 @@ -77,6 +146,12 @@ char *get_host_id(void) g_key_file_free(key_file); g_free(config_file); + if (!host_id) { + //no config, generate host_id + host_id = lockdownd_generate_hostid(); + write_host_id(host_id); + } + log_debug_msg("get_host_id(): Using %s as HostID\n", host_id); return host_id; } @@ -156,56 +231,220 @@ static int read_file_in_confdir(const char *file, gnutls_datum_t * data) g_free(filepath); /* Add it to the gnutls_datnum_t structure */ - data->data = content; + data->data = (uint8_t*) content; data->size = size; return success; } -/** Read the root private key - * - * @param root_privkey A pointer to the appropriate gnutls structure + +/** Private function which generate private keys and certificates. * - * @return 1 if the file was successfully read and 0 otherwise. + * @return IPHONE_E_SUCCESS if keys were successfully generated. */ -int get_root_private_key(gnutls_datum_t * root_privkey) +static iphone_error_t gen_keys_and_cert(void) { - return read_file_in_confdir(LIBIPHONE_ROOT_PRIVKEY, root_privkey); + iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + gnutls_x509_privkey_t root_privkey; + gnutls_x509_privkey_t host_privkey; + gnutls_x509_crt_t root_cert; + gnutls_x509_crt_t host_cert; + + gnutls_global_deinit(); + gnutls_global_init(); + + //use less secure random to speed up key generation + gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM); + + 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 root key */ + gnutls_x509_privkey_generate(root_privkey, GNUTLS_PK_RSA, 2048, 0); + gnutls_x509_privkey_generate(host_privkey, GNUTLS_PK_RSA, 2048, 0); + + /* 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); + + gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_pem.size); + gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_pem.size); + + if (NULL != root_cert_pem.data && 0 != root_cert_pem.size && + NULL != host_cert_pem.data && 0 != host_cert_pem.size) + ret = IPHONE_E_SUCCESS; + + /* store values in config file */ + init_config_file( &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); + + //restore gnutls env + gnutls_global_deinit(); + gnutls_global_init(); + + return ret; } -/** Read the host private key +/** Private function which import the given key into a gnutls structure. * - * @param host_privkey A pointer to the appropriate gnutls structure + * @param key_name The filename of the private key to import. + * @param key the gnutls key structure. * - * @return 1 if the file was successfully read and 0 otherwise. + * @return IPHONE_E_SUCCESS if the key was successfully imported. */ -int get_host_private_key(gnutls_datum_t * host_privkey) +static iphone_error_t import_key(const char* key_name, gnutls_x509_privkey_t key) { - return read_file_in_confdir(LIBIPHONE_HOST_PRIVKEY, host_privkey); + iphone_error_t ret = IPHONE_E_INVALID_CONF; + gnutls_datum_t pem_key = { NULL, 0 }; + + if ( read_file_in_confdir(key_name, &pem_key) ) { + if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM)) + ret = IPHONE_E_SUCCESS; + else + ret = IPHONE_E_SSL_ERROR; + } + gnutls_free(pem_key.data); + return ret; } -/** Read the root certificate +/** Private function which import the given certificate into a gnutls structure. * - * @param root_privkey A pointer to the appropriate gnutls structure + * @param crt_name The filename of the certificate to import. + * @param cert the gnutls certificate structure. * - * @return 1 if the file was successfully read and 0 otherwise. + * @return IPHONE_E_SUCCESS if the certificate was successfully imported. */ -int get_root_certificate(gnutls_datum_t * root_cert) +static iphone_error_t import_crt(const char* crt_name, gnutls_x509_crt_t cert) { - return read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, root_cert); + iphone_error_t ret = IPHONE_E_INVALID_CONF; + gnutls_datum_t pem_cert = { NULL, 0 }; + + if ( read_file_in_confdir(crt_name, &pem_cert) ) { + if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM)) + ret = IPHONE_E_SUCCESS; + else + ret = IPHONE_E_SSL_ERROR; + } + gnutls_free(pem_cert.data); + return ret; } -/** Read the host certificate +/** Function to retrieve host keys and certificates. + * This function trigger key generation if they do not exists yet or are invalid. * - * @param root_privkey A pointer to the appropriate gnutls structure + * @note This function can take few seconds to complete (typically 5 seconds) * - * @return 1 if the file was successfully read and 0 otherwise. + * @param root_privkey The root private key. + * @param root_crt The root certificate. + * @param host_privkey The host private key. + * @param host_crt The host certificate. + * + * @return IPHONE_E_SUCCESS if the keys and certificates were successfully retrieved. */ -int get_host_certificate(gnutls_datum_t * host_cert) +iphone_error_t get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt) { - return read_file_in_confdir(LIBIPHONE_HOST_CERTIF, host_cert); + iphone_error_t ret = IPHONE_E_SUCCESS; + + if (ret == IPHONE_E_SUCCESS) + ret = import_key(LIBIPHONE_ROOT_PRIVKEY, root_privkey); + + if (ret == IPHONE_E_SUCCESS) + ret = import_key(LIBIPHONE_HOST_PRIVKEY, host_privkey); + + if (ret == IPHONE_E_SUCCESS) + ret = import_crt(LIBIPHONE_ROOT_CERTIF, root_crt); + + if (ret == IPHONE_E_SUCCESS) + ret = import_crt(LIBIPHONE_HOST_CERTIF, host_crt); + + + if (IPHONE_E_SUCCESS != ret) { + //we had problem reading or importing root cert + //try with a new ones. + ret = gen_keys_and_cert(); + + if (ret == IPHONE_E_SUCCESS) + ret = import_key(LIBIPHONE_ROOT_PRIVKEY, root_privkey); + + if (ret == IPHONE_E_SUCCESS) + ret = import_key(LIBIPHONE_HOST_PRIVKEY, host_privkey); + + if (ret == IPHONE_E_SUCCESS) + ret = import_crt(LIBIPHONE_ROOT_CERTIF, root_crt); + + if (ret == IPHONE_E_SUCCESS) + ret = import_crt(LIBIPHONE_HOST_CERTIF, host_crt); + } + + return ret; } +/** Function to retrieve certificates encoded in PEM format. + * + * @param pem_root_cert The root certificate. + * @param pem_host_cert The host certificate. + * + * @return IPHONE_E_SUCCESS if the certificates were successfully retrieved. + */ +iphone_error_t get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert) +{ + iphone_error_t ret = IPHONE_E_INVALID_CONF; + + if ( !pem_root_cert || !pem_host_cert) + return IPHONE_E_INVALID_ARG; + + if ( read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, pem_root_cert) && read_file_in_confdir(LIBIPHONE_HOST_CERTIF, pem_host_cert)) + ret = IPHONE_E_SUCCESS; + else { + g_free(pem_root_cert->data); + g_free(pem_host_cert->data); + } + return ret; +} /** Create and save a configuration file containing the given data. * * @note: All fields must specified and be non-null @@ -218,41 +457,18 @@ int get_host_certificate(gnutls_datum_t * host_cert) * * @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, +int init_config_file( 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) + if (!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"); diff --git a/src/userpref.h b/src/userpref.h index 7e606eb..deced04 100644 --- a/src/userpref.h +++ b/src/userpref.h @@ -8,64 +8,34 @@ * 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 + * 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(void); +#include "libiphone/libiphone.h" -/** - * 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); +iphone_error_t get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt); -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_root_private_key(gnutls_datum_t * root_privkey); +iphone_error_t get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert); -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_host_private_key(gnutls_datum_t * host_privkey); +char *get_host_id(void); -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_root_certificate(gnutls_datum_t * root_cert); +int is_device_known(char *uid); -/** - * @return 1 if everything went well. Returns 0 otherwise. - */ -int get_host_certificate(gnutls_datum_t * host_cert); +int store_device_public_key(char *uid, gnutls_datum_t public_key); -/** - * 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, +int init_config_file( 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 From 620b6315b03e2dff3067b8fe9bae4d5486009ba4 Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 13 Apr 2009 10:05:30 +0200 Subject: Add libtool dependency in README. --- README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index 955da4e..7ee438a 100644 --- a/README +++ b/README @@ -16,6 +16,7 @@ You must have: autoheader automake autoconf + libtool gcc To compile run: @@ -25,8 +26,8 @@ To compile run: sudo make install # (if you want to install it into your system directories) 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 \ + sudo apt-get install build-essential automake autoconf libtool \ + libgnutls-dev libusb-dev libfuse-dev libglib2.0-dev \ libreadline5-dev == Who/what/where? == -- cgit v1.1-32-gdbae From 288929f45cb2641690879b52ec514097995cd41a Mon Sep 17 00:00:00 2001 From: Jonathan Beck Date: Mon, 13 Apr 2009 10:06:42 +0200 Subject: Conform to python naling scheme. Add docstring directive. --- swig/iphone.i | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/swig/iphone.i b/swig/iphone.i index e970e89..3ae0999 100644 --- a/swig/iphone.i +++ b/swig/iphone.i @@ -1,5 +1,6 @@ /* swig.i */ %module(package="libiphone") iPhone + %feature("autodoc", "1"); %{ /* Includes the header in the wrapper code */ #include @@ -105,13 +106,13 @@ MobileSync* my_new_MobileSync(Lockdownd* lckd) { my_delete_iPhone($self); } - int InitDevice() { + int init_device() { if (IPHONE_E_SUCCESS == iphone_get_device ( &($self->dev))) return 1; return 0; } - Lockdownd* GetLockdownClient() { + Lockdownd* get_lockdown_client() { return my_new_Lockdownd($self); } }; @@ -126,7 +127,7 @@ MobileSync* my_new_MobileSync(Lockdownd* lckd) { my_delete_Lockdownd($self); } - MobileSync* GetMobileSyncClient() { + MobileSync* get_mobile_sync_client() { return my_new_MobileSync($self); } }; @@ -142,11 +143,11 @@ MobileSync* my_new_MobileSync(Lockdownd* lckd) { free($self); } - void Send(PListNode* node) { + void send(PListNode* node) { iphone_msync_send($self->client, node->node); } - PListNode* Receive() { + PListNode* receive() { PListNode* node = (PListNode*)malloc(sizeof(PListNode)); node->node = NULL; iphone_msync_recv($self->client, &(node->node)); -- cgit v1.1-32-gdbae