summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/initconf.c30
-rw-r--r--src/lockdown.c27
-rw-r--r--src/lockdown.h2
-rw-r--r--src/plist.c1118
-rw-r--r--src/plist.h15
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) $
6bin_PROGRAMS = libiphone-initconf 6bin_PROGRAMS = libiphone-initconf
7 7
8 8
9libiphone_initconf_SOURCES = initconf.c userpref.c lockdown.c plist.c usbmux.c iphone.c utils.c 9libiphone_initconf_SOURCES = initconf.c userpref.c utils.c
10libiphone_initconf_CFLAGS = $(libgthread2_CFLAGS) $(AM_CFLAGS) 10libiphone_initconf_CFLAGS = $(libgthread2_CFLAGS) $(AM_CFLAGS)
11libiphone_initconf_LDFLAGS = $(libgthread2_LIBS) $(AM_LDFLAGS) 11libiphone_initconf_LDFLAGS = $(libgthread2_LIBS) $(AM_LDFLAGS)
12 12
13 13
14lib_LTLIBRARIES = libiphone.la 14lib_LTLIBRARIES = libiphone.la
15libiphone_la_SOURCES = usbmux.c iphone.c plist.c lockdown.c AFC.c userpref.c utils.c 15libiphone_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 @@
28 28
29#include "libiphone/libiphone.h" 29#include "libiphone/libiphone.h"
30#include "userpref.h" 30#include "userpref.h"
31#include "lockdown.h"
32#include "utils.h" 31#include "utils.h"
33 32
34/** Generates a 2048 byte key, split into a function so that it can be run in a 33/** 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)
60 g_thread_exit(0); 59 g_thread_exit(0);
61} 60}
62 61
62int get_rand(int min, int max)
63{
64 int retval = (rand() % (max - min)) + min;
65 return retval;
66}
67
68/** Generates a valid HostID (which is actually a UUID).
69 *
70 * @param A null terminated string containing a valid HostID.
71 */
72char *lockdownd_generate_hostid()
73{
74 char *hostid = (char *) malloc(sizeof(char) * 37); // HostID's are just UUID's, and UUID's are 36 characters long
75 const char *chars = "ABCDEF0123456789";
76 srand(time(NULL));
77 int i = 0;
78
79 for (i = 0; i < 36; i++) {
80 if (i == 8 || i == 13 || i == 18 || i == 23) {
81 hostid[i] = '-';
82 continue;
83 } else {
84 hostid[i] = chars[get_rand(0, 16)];
85 }
86 }
87 hostid[36] = '\0'; // make it a real string
88 return hostid;
89}
90
63int main(int argc, char *argv[]) 91int main(int argc, char *argv[])
64{ 92{
65 GThread *progress_thread, *key_thread; 93 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[] = {
39 {0, 0, 0} 39 {0, 0, 0}
40}; 40};
41 41
42int get_rand(int min, int max)
43{
44 int retval = (rand() % (max - min)) + min;
45 return retval;
46}
47 42
48/** Generates a valid HostID (which is actually a UUID).
49 *
50 * @param A null terminated string containing a valid HostID.
51 */
52char *lockdownd_generate_hostid()
53{
54 char *hostid = (char *) malloc(sizeof(char) * 37); // HostID's are just UUID's, and UUID's are 36 characters long
55 const char *chars = "ABCDEF0123456789";
56 srand(time(NULL));
57 int i = 0;
58
59 for (i = 0; i < 36; i++) {
60 if (i == 8 || i == 13 || i == 18 || i == 23) {
61 hostid[i] = '-';
62 continue;
63 } else {
64 hostid[i] = chars[get_rand(0, 16)];
65 }
66 }
67 hostid[36] = '\0'; // make it a real string
68 return hostid;
69}
70 43
71/** Creates a lockdownd client for the give iPhone. 44/** Creates a lockdownd client for the give iPhone.
72 * 45 *
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 {
40 int gtls_buffer_hack_len; 40 int gtls_buffer_hack_len;
41}; 41};
42 42
43char *lockdownd_generate_hostid();
44
45iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone); 43iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone);
46iphone_error_t lockdownd_hello(iphone_lckd_client_t control); 44iphone_error_t lockdownd_hello(iphone_lckd_client_t control);
47iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *req_key, char *req_string, char **value); 45iphone_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 @@
28#include <stdlib.h> 28#include <stdlib.h>
29#include <stdio.h> 29#include <stdio.h>
30 30
31/**********************************************
32* *
33* Abstract Plist stuff *
34* *
35**********************************************/
36
37
38
39
40
41
42
43/** Formats a block of text to be a given indentation and width.
44 *
45 * The total width of the return string will be depth + cols.
46 *
47 * @param buf The string to format.
48 * @param cols The number of text columns for returned block of text.
49 * @param depth The number of tabs to indent the returned block of text.
50 *
51 * @return The formatted string.
52 */
53char *format_string(const char *buf, int cols, int depth)
54{
55 int colw = depth + cols + 1;
56 int len = strlen(buf);
57 int nlines = len / cols + 1;
58 char *new_buf = (char *) malloc(nlines * colw + depth + 1);
59 int i = 0;
60 int j = 0;
61
62 assert(cols >= 0);
63 assert(depth >= 0);
64
65 // Inserts new lines and tabs at appropriate locations
66 for (i = 0; i < nlines; i++) {
67 new_buf[i * colw] = '\n';
68 for (j = 0; j < depth; j++)
69 new_buf[i * colw + 1 + j] = '\t';
70 memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols);
71 }
72 new_buf[len + (1 + depth) * nlines] = '\n';
73
74 // Inserts final row of indentation and termination character
75 for (j = 0; j < depth; j++)
76 new_buf[len + (1 + depth) * nlines + 1 + j] = '\t';
77 new_buf[len + (1 + depth) * nlines + depth + 1] = '\0';
78
79 return new_buf;
80}
81
82
83
84
85/*
86 * Binary propertylist code follows
87 */
88
89
90/*
91 * This is how parsing a bplist is going to have to work:
92 * - The entire binary plist is going to have to be in memory.
93 * - A function, parse_nodes(), will have to be a recursive function
94 * which iterates over the binary plist and reads in elements into bplist_node structs
95 * and handles them accordingly. The end result should be a somewhat-hierarchical layout
96 * of bplist_nodes.
97 * - parse_nodes() will return the first node it encounters, which is usually the "root" node.
98 */
99
100
101
102void print_bytes(char *val, size_t size)
103{
104 int i = 0;
105 for (i = 0; i < size; i++) {
106 printf("Byte %i: 0x%x\n", i, val[i]);
107 }
108}
109
110
111
112struct plist_data {
113 union {
114 char boolval;
115 uint64_t intval;
116 double realval;
117 char *strval;
118 wchar_t *unicodeval;
119 char *buff;
120 };
121 uint64_t length;
122 plist_type type;
123};
124
125
126 31
127void plist_new_plist(plist_t * plist) 32void plist_new_plist(plist_t * plist)
128{ 33{
@@ -205,683 +110,6 @@ void plist_free(plist_t plist)
205 g_node_destroy(plist); 110 g_node_destroy(plist);
206} 111}
207 112
208/**********************************************
209* *
210* Xml Plist stuff *
211* *
212**********************************************/
213
214#include <libxml/parser.h>
215#include <libxml/tree.h>
216
217
218const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
219<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
220<plist version=\"1.0\">\n\
221</plist>\0";
222
223struct xml_node {
224 xmlNodePtr xml;
225 uint32_t depth;
226};
227
228/** Creates a new plist XML document.
229 *
230 * @return The plist XML document.
231 */
232xmlDocPtr new_plist()
233{
234 char *plist = strdup(plist_base);
235 xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0);
236
237 if (!plist_xml)
238 return NULL;
239
240 free(plist);
241
242 return plist_xml;
243}
244
245/** Destroys a previously created XML document.
246 *
247 * @param plist The XML document to destroy.
248 */
249void free_plist(xmlDocPtr plist)
250{
251 if (!plist)
252 return;
253
254 xmlFreeDoc(plist);
255}
256
257void node_to_xml(GNode * node, gpointer xml_struct)
258{
259 if (!node)
260 return;
261
262 struct xml_node *xstruct = (struct xml_node *) xml_struct;
263 struct plist_data *node_data = (struct plist_data *) node->data;
264
265 xmlNodePtr child_node = NULL;
266 char isStruct = FALSE;
267
268 gchar *tag = NULL;
269 gchar *val = NULL;
270
271 switch (node_data->type) {
272 case PLIST_BOOLEAN:
273 {
274 if (node_data->boolval)
275 tag = "true";
276 else
277 tag = "false";
278 }
279 break;
280
281 case PLIST_UINT:
282 tag = "integer";
283 val = g_strdup_printf("%lu", (long unsigned int) node_data->intval);
284 break;
285
286 case PLIST_REAL:
287 tag = "real";
288 val = g_strdup_printf("%Lf", (long double) node_data->realval);
289 break;
290
291 case PLIST_STRING:
292 tag = "string";
293 val = g_strdup(node_data->strval);
294 break;
295
296 case PLIST_UNICODE:
297 tag = "string";
298 val = g_strdup((gchar *) node_data->unicodeval);
299 break;
300
301 case PLIST_KEY:
302 tag = "key";
303 val = g_strdup((gchar *) node_data->strval);
304 break;
305
306 case PLIST_DATA:
307 tag = "data";
308 val = format_string(node_data->buff, 60, xstruct->depth);
309 break;
310 case PLIST_ARRAY:
311 tag = "array";
312 isStruct = TRUE;
313 break;
314 case PLIST_DICT:
315 tag = "dict";
316 isStruct = TRUE;
317 break;
318 case PLIST_DATE: //TODO : handle date tag
319 default:
320 break;
321 }
322
323 int i = 0;
324 for (i = 0; i < xstruct->depth; i++) {
325 xmlNodeAddContent(xstruct->xml, "\t");
326 }
327 child_node = xmlNewChild(xstruct->xml, NULL, tag, val);
328 xmlNodeAddContent(xstruct->xml, "\n");
329 g_free(val);
330
331 //add return for structured types
332 if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA)
333 xmlNodeAddContent(child_node, "\n");
334
335 if (isStruct) {
336 struct xml_node child = { child_node, xstruct->depth + 1 };
337 g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child);
338 }
339 //fix indent for structured types
340 if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) {
341
342 for (i = 0; i < xstruct->depth; i++) {
343 xmlNodeAddContent(child_node, "\t");
344 }
345 }
346
347 return;
348}
349
350void xml_to_node(xmlNodePtr xml_node, GNode * plist_node)
351{
352 xmlNodePtr node = NULL;
353
354 for (node = xml_node->children; node; node = node->next) {
355
356 while (node && !xmlStrcmp(node->name, "text"))
357 node = node->next;
358 if (!node)
359 break;
360
361 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
362 GNode *subnode = g_node_new(data);
363 g_node_append(plist_node, subnode);
364
365 if (!xmlStrcmp(node->name, "true")) {
366 data->boolval = 1;
367 data->type = PLIST_BOOLEAN;
368 continue;
369 }
370
371 if (!xmlStrcmp(node->name, "false")) {
372 data->boolval = 0;
373 data->type = PLIST_BOOLEAN;
374 continue;
375 }
376
377 if (!xmlStrcmp(node->name, "integer")) {
378 char *strval = xmlNodeGetContent(node);
379 data->intval = atoi(strval);
380 data->type = PLIST_UINT;
381 continue;
382 }
383
384 if (!xmlStrcmp(node->name, "real")) {
385 char *strval = xmlNodeGetContent(node);
386 data->realval = atof(strval);
387 data->type = PLIST_REAL;
388 continue;
389 }
390
391 if (!xmlStrcmp(node->name, "date"))
392 continue; //TODO : handle date tag
393
394 if (!xmlStrcmp(node->name, "string")) {
395 data->strval = strdup(xmlNodeGetContent(node));
396 data->type = PLIST_STRING;
397 continue;
398 }
399
400 if (!xmlStrcmp(node->name, "key")) {
401 data->strval = strdup(xmlNodeGetContent(node));
402 data->type = PLIST_KEY;
403 continue;
404 }
405
406 if (!xmlStrcmp(node->name, "data")) {
407 data->buff = strdup(xmlNodeGetContent(node));
408 data->type = PLIST_DATA;
409 continue;
410 }
411
412 if (!xmlStrcmp(node->name, "array")) {
413 data->type = PLIST_ARRAY;
414 xml_to_node(node, subnode);
415 continue;
416 }
417
418 if (!xmlStrcmp(node->name, "dict")) {
419 data->type = PLIST_DICT;
420 xml_to_node(node, subnode);
421 continue;
422 }
423 }
424}
425
426void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)
427{
428 if (!plist || !plist_xml || *plist_xml)
429 return;
430 xmlDocPtr plist_doc = new_plist();
431 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
432 struct xml_node root = { root_node, 0 };
433 g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root);
434 xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length);
435}
436
437void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist)
438{
439 xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0);
440 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
441
442 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
443 *plist = g_node_new(data);
444 data->type = PLIST_DICT;
445 xml_to_node(root_node, *plist);
446}
447
448
449
450/**********************************************
451* *
452* Binary Plist stuff *
453* *
454**********************************************/
455
456/* Magic marker and size. */
457#define BPLIST_MAGIC "bplist"
458#define BPLIST_MAGIC_SIZE 6
459
460#define BPLIST_VERSION "00"
461#define BPLIST_VERSION_SIZE 2
462
463
464#define BPLIST_TRL_SIZE 26
465#define BPLIST_TRL_OFFSIZE_IDX 0
466#define BPLIST_TRL_PARMSIZE_IDX 1
467#define BPLIST_TRL_NUMOBJ_IDX 2
468#define BPLIST_TRL_ROOTOBJ_IDX 10
469#define BPLIST_TRL_OFFTAB_IDX 18
470
471enum {
472 BPLIST_NULL = 0x00,
473 BPLIST_TRUE = 0x08,
474 BPLIST_FALSE = 0x09,
475 BPLIST_FILL = 0x0F, /* will be used for length grabbing */
476 BPLIST_UINT = 0x10,
477 BPLIST_REAL = 0x20,
478 BPLIST_DATE = 0x30,
479 BPLIST_DATA = 0x40,
480 BPLIST_STRING = 0x50,
481 BPLIST_UNICODE = 0x60,
482 BPLIST_UID = 0x70,
483 BPLIST_ARRAY = 0xA0,
484 BPLIST_SET = 0xC0,
485 BPLIST_DICT = 0xD0,
486 BPLIST_MASK = 0xF0
487};
488
489void byte_convert(char *address, size_t size)
490{
491 int i = 0, j = 0;
492 char tmp = '\0';
493
494 for (i = 0; i < (size / 2); i++) {
495 tmp = address[i];
496 j = ((size - 1) + 0) - i;
497 address[i] = address[j];
498 address[j] = tmp;
499 }
500}
501
502#include <byteswap.h>
503#define swap_n_bytes(x, n) \
504 n == 8 ? bswap_64(*(uint64_t *)(x)) : \
505 (n == 4 ? bswap_32(*(uint32_t *)(x)) : \
506 (n == 2 ? bswap_16(*(uint16_t *)(x)) : *(x) ))
507
508#define be64dec(x) bswap_64( *(uint64_t*)(x) )
509
510#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= 1<<32 ? 4 : 8)))
511#define get_real_bytes(x) (x >> 32 ? 4 : 8)
512
513GNode *parse_uint_node(char *bnode, uint8_t size, char **next_object)
514{
515 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
516
517 size = 1 << size; // make length less misleading
518 switch (size) {
519 case sizeof(uint8_t):
520 data->intval = bnode[0];
521 break;
522 case sizeof(uint16_t):
523 memcpy(&data->intval, bnode, size);
524 data->intval = ntohs(data->intval);
525 break;
526 case sizeof(uint32_t):
527 memcpy(&data->intval, bnode, size);
528 data->intval = ntohl(data->intval);
529 break;
530 case sizeof(uint64_t):
531 memcpy(&data->intval, bnode, size);
532 byte_convert((char *) &data->intval, size);
533 break;
534 default:
535 free(data);
536 return NULL;
537 };
538
539 *next_object = bnode + size;
540 data->type = PLIST_UINT;
541 return g_node_new(data);
542}
543
544GNode *parse_real_node(char *bnode, uint8_t size)
545{
546 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
547
548 size = 1 << size; // make length less misleading
549 switch (size) {
550 case sizeof(float):
551 memcpy(&data->realval, bnode, size);
552 byte_convert((char *) &data->realval, size);
553 break;
554 case sizeof(double):
555 memcpy(&data->realval, bnode, size);
556 byte_convert((char *) &data->realval, size);
557 break;
558 default:
559 free(data);
560 return NULL;
561 }
562 data->type = PLIST_REAL;
563 return g_node_new(data);
564}
565
566GNode *parse_string_node(char *bnode, uint8_t size)
567{
568 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
569
570 data->type = PLIST_STRING;
571 data->strval = (char *) malloc(sizeof(char) * (size + 1));
572 memcpy(data->strval, bnode, size);
573 data->strval[size] = '\0';
574
575 return g_node_new(data);
576}
577
578GNode *parse_unicode_node(char *bnode, uint8_t size)
579{
580 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
581
582 data->type = PLIST_UNICODE;
583 data->unicodeval = (wchar_t *) malloc(sizeof(wchar_t) * (size + 1));
584 memcpy(data->unicodeval, bnode, size);
585 data->unicodeval[size] = '\0';
586
587 return g_node_new(data);
588}
589
590GNode *parse_data_node(char *bnode, uint64_t size, uint32_t ref_size)
591{
592 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
593
594 data->type = PLIST_DATA;
595 data->length = size;
596 data->buff = (char *) malloc(sizeof(char) * size);
597 memcpy(data->buff, bnode, sizeof(char) * size);
598
599 return g_node_new(data);
600}
601
602GNode *parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size)
603{
604 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
605
606 data->type = PLIST_DICT;
607 data->length = size;
608 data->buff = (char *) malloc(sizeof(char) * size * ref_size * 2);
609 memcpy(data->buff, bnode, sizeof(char) * size * ref_size * 2);
610
611 return g_node_new(data);
612}
613
614GNode *parse_array_node(char *bnode, uint64_t size, uint32_t ref_size)
615{
616 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
617
618 data->type = PLIST_ARRAY;
619 data->length = size;
620 data->buff = (char *) malloc(sizeof(char) * size * ref_size);
621 memcpy(data->buff, bnode, sizeof(char) * size * ref_size);
622
623 return g_node_new(data);
624}
625
626plist_type plist_get_node_type(plist_t node)
627{
628 return ((struct plist_data *) node->data)->type;
629}
630
631uint64_t plist_get_node_uint_val(plist_t node)
632{
633 if (PLIST_UINT == plist_get_node_type(node))
634 return ((struct plist_data *) node->data)->intval;
635 else
636 return 0;
637}
638
639GNode *parse_bin_node(char *object, uint8_t dict_size, char **next_object)
640{
641 if (!object)
642 return NULL;
643
644 uint16_t type = *object & 0xF0;
645 uint64_t size = *object & 0x0F;
646 object++;
647
648 switch (type) {
649
650 case BPLIST_NULL:
651 switch (size) {
652
653 case BPLIST_TRUE:
654 {
655 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
656 data->type = PLIST_BOOLEAN;
657 data->boolval = TRUE;
658 return g_node_new(data);
659 }
660
661 case BPLIST_FALSE:
662 {
663 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
664 data->type = PLIST_BOOLEAN;
665 data->boolval = FALSE;
666 return g_node_new(data);
667 }
668
669 case BPLIST_NULL:
670 default:
671 return NULL;
672 }
673
674 case BPLIST_UINT:
675 return parse_uint_node(object, size, next_object);
676
677 case BPLIST_REAL:
678 return parse_real_node(object, size);
679
680 case BPLIST_DATE:
681 if (3 != size)
682 return NULL;
683 else
684 return parse_real_node(object, size);
685
686 case BPLIST_DATA:
687 if (0x0F == size) {
688 plist_t size_node = parse_bin_node(object, dict_size, &object);
689 if (plist_get_node_type(size_node) != PLIST_UINT)
690 return NULL;
691 size = plist_get_node_uint_val(size_node);
692 }
693 return parse_data_node(object, size, dict_size);
694
695 case BPLIST_STRING:
696 if (0x0F == size) {
697 plist_t size_node = parse_bin_node(object, dict_size, &object);
698 if (plist_get_node_type(size_node) != PLIST_UINT)
699 return NULL;
700 size = plist_get_node_uint_val(size_node);
701 }
702 return parse_string_node(object, size);
703
704 case BPLIST_UNICODE:
705 if (0x0F == size) {
706 plist_t size_node = parse_bin_node(object, dict_size, &object);
707 if (plist_get_node_type(size_node) != PLIST_UINT)
708 return NULL;
709 size = plist_get_node_uint_val(size_node);
710 }
711 return parse_unicode_node(object, size);
712
713 case BPLIST_UID:
714 case BPLIST_ARRAY:
715 if (0x0F == size) {
716 plist_t size_node = parse_bin_node(object, dict_size, &object);
717 if (plist_get_node_type(size_node) != PLIST_UINT)
718 return NULL;
719 size = plist_get_node_uint_val(size_node);
720 }
721 return parse_array_node(object, size, dict_size);
722
723 case BPLIST_SET:
724 case BPLIST_DICT:
725 if (0x0F == size) {
726 plist_t size_node = parse_bin_node(object, dict_size, &object);
727 if (plist_get_node_type(size_node) != PLIST_UINT)
728 return NULL;
729 object++;
730 size = plist_get_node_uint_val(size_node);
731 }
732 return parse_dict_node(object, size, dict_size);
733
734 }
735 return NULL;
736}
737
738gpointer copy_plist_data(gconstpointer src, gpointer data)
739{
740 struct plist_data *srcdata = (struct plist_data *) src;
741 struct plist_data *dstdata = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
742
743 dstdata->type = srcdata->type;
744 dstdata->length = srcdata->length;
745 switch (dstdata->type) {
746 case PLIST_BOOLEAN:
747 dstdata->boolval = srcdata->boolval;
748 break;
749 case PLIST_UINT:
750 dstdata->intval = srcdata->intval;
751 break;
752 case PLIST_DATE:
753 case PLIST_REAL:
754 dstdata->realval = srcdata->realval;
755 break;
756 case PLIST_KEY:
757 case PLIST_STRING:
758 dstdata->strval = strdup(srcdata->strval);
759 break;
760 case PLIST_UNICODE:
761 dstdata->unicodeval = wcsdup(srcdata->unicodeval);
762 break;
763 case PLIST_DATA:
764 case PLIST_ARRAY:
765 case PLIST_DICT:
766 dstdata->buff = (char *) malloc(sizeof(char *) * srcdata->length);
767 memcpy(dstdata->buff, srcdata->buff, sizeof(char *) * srcdata->length);
768 break;
769
770 default:
771 break;
772 }
773
774 return dstdata;
775}
776
777void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist)
778{
779 //first check we have enough data
780 if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE))
781 return;
782 //check that plist_bin in actually a plist
783 if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0)
784 return;
785 //check for known version
786 if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0)
787 return;
788
789 //now parse trailer
790 const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE);
791
792 uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX];
793 uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX];
794 uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX);
795 uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX);
796 uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX);
797
798 log_debug_msg("Offset size: %i\n", offset_size);
799 log_debug_msg("Ref size: %i\n", dict_param_size);
800 log_debug_msg("Number of objects: %lli\n", num_objects);
801 log_debug_msg("Root object index: %lli\n", root_object);
802 log_debug_msg("Offset table index: %lli\n", offset_table_index);
803
804 if (num_objects == 0)
805 return;
806
807 //allocate serialized array of nodes
808 plist_t *nodeslist = NULL;
809 nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects);
810
811 if (!nodeslist)
812 return;
813
814 //parse serialized nodes
815 uint64_t i = 0;
816 uint64_t current_offset = 0;
817 const char *offset_table = plist_bin + offset_table_index;
818 for (i = 0; i < num_objects; i++) {
819 current_offset = swap_n_bytes(offset_table + i * offset_size, offset_size);
820
821 log_debug_msg("parse_nodes: current_offset = %i\n", current_offset);
822 char *obj = plist_bin + current_offset;
823 nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj);
824 log_debug_msg("parse_nodes: parse_raw_node done\n");
825 }
826
827 //setup children for structured types
828 int j = 0, str_i = 0, str_j = 0;
829 uint32_t index1 = 0, index2 = 0;
830
831 for (i = 0; i < num_objects; i++) {
832
833 log_debug_msg("parse_nodes: on node %i\n", i);
834 struct plist_data *data = (struct plist_data *) nodeslist[i]->data;
835
836 switch (data->type) {
837 case PLIST_DICT:
838 log_debug_msg("parse_nodes: dictionary found\n");
839 for (j = 0; j < data->length; j++) {
840 str_i = j * dict_param_size;
841 str_j = (j + data->length) * dict_param_size;
842
843 index1 = swap_n_bytes(data->buff + str_i, dict_param_size);
844 index2 = swap_n_bytes(data->buff + str_j, dict_param_size);
845
846 //first one is actually a key
847 ((struct plist_data *) nodeslist[index1]->data)->type = PLIST_KEY;
848
849 if (G_NODE_IS_ROOT(nodeslist[index1]))
850 g_node_append(nodeslist[i], nodeslist[index1]);
851 else
852 g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL));
853
854 if (G_NODE_IS_ROOT(nodeslist[index2]))
855 g_node_append(nodeslist[i], nodeslist[index2]);
856 else
857 g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index2], copy_plist_data, NULL));
858 }
859
860 free(data->buff);
861 break;
862
863 case PLIST_ARRAY:
864 log_debug_msg("parse_nodes: array found\n");
865 for (j = 0; j < data->length; j++) {
866 str_j = j * dict_param_size;
867 index1 = swap_n_bytes(data->buff + str_j, dict_param_size);
868
869 //g_node_append(nodeslist[i], nodeslist[index1]);
870 if (G_NODE_IS_ROOT(nodeslist[index1]))
871 g_node_append(nodeslist[i], nodeslist[index1]);
872 else
873 g_node_append(nodeslist[i], g_node_copy_deep(nodeslist[index1], copy_plist_data, NULL));
874 }
875 free(data->buff);
876 break;
877 default:
878 break;
879 }
880 }
881
882 *plist = nodeslist[root_object];
883}
884
885GNode *find_query_node(plist_t plist, char *key, char *request) 113GNode *find_query_node(plist_t plist, char *key, char *request)
886{ 114{
887 if (!plist) 115 if (!plist)
@@ -998,347 +226,15 @@ void get_type_and_value(GNode * node, plist_type * type, void *value)
998 } 226 }
999} 227}
1000 228
1001guint plist_data_hash(gconstpointer key) 229plist_type plist_get_node_type(plist_t node)
1002{
1003 struct plist_data *data = (struct plist_data *) ((GNode *) key)->data;
1004
1005 guint hash = data->type;
1006 guint i = 0;
1007
1008 char *buff = NULL;
1009 guint size = 0;
1010
1011 switch (data->type) {
1012 case PLIST_BOOLEAN:
1013 case PLIST_UINT:
1014 case PLIST_REAL:
1015 buff = (char *) &data->intval;
1016 size = 8;
1017 break;
1018 case PLIST_KEY:
1019 case PLIST_STRING:
1020 buff = data->strval;
1021 size = strlen(buff);
1022 break;
1023 case PLIST_UNICODE:
1024 buff = data->unicodeval;
1025 size = strlen(buff) * sizeof(wchar_t);
1026 break;
1027 case PLIST_DATA:
1028 case PLIST_ARRAY:
1029 case PLIST_DICT:
1030 //for these types only hash pointer
1031 buff = &key;
1032 size = sizeof(gconstpointer);
1033 break;
1034 case PLIST_DATE:
1035 default:
1036 break;
1037 }
1038
1039 //now perform hash
1040 for (i = 0; i < size; buff++, i++)
1041 hash = hash << 7 ^ (*buff);
1042
1043 return hash;
1044}
1045
1046gboolean plist_data_compare(gconstpointer a, gconstpointer b)
1047{
1048 if (!a || !b)
1049 return FALSE;
1050
1051 if (!((GNode *) a)->data || !((GNode *) b)->data)
1052 return FALSE;
1053
1054 struct plist_data *val_a = (struct plist_data *) ((GNode *) a)->data;
1055 struct plist_data *val_b = (struct plist_data *) ((GNode *) b)->data;
1056
1057 if (val_a->type != val_b->type)
1058 return FALSE;
1059
1060 switch (val_a->type) {
1061 case PLIST_BOOLEAN:
1062 case PLIST_UINT:
1063 case PLIST_REAL:
1064 if (val_a->intval == val_b->intval) //it is an union so this is sufficient
1065 return TRUE;
1066 else
1067 return FALSE;
1068
1069 case PLIST_KEY:
1070 case PLIST_STRING:
1071 if (!strcmp(val_a->strval, val_b->strval))
1072 return TRUE;
1073 else
1074 return FALSE;
1075 case PLIST_UNICODE:
1076 if (!strcmp(val_a->unicodeval, val_b->unicodeval))
1077 return TRUE;
1078 else
1079 return FALSE;
1080
1081 case PLIST_DATA:
1082 case PLIST_ARRAY:
1083 case PLIST_DICT:
1084 //compare pointer
1085 if (a == b)
1086 return TRUE;
1087 else
1088 return FALSE;
1089 break;
1090 case PLIST_DATE:
1091 default:
1092 break;
1093 }
1094 return FALSE;
1095}
1096
1097struct serialize_s {
1098 GPtrArray *objects;
1099 GHashTable *ref_table;
1100};
1101
1102void serialize_plist(GNode * node, gpointer data)
1103{
1104 struct serialize_s *ser = (struct serialize_s *) data;
1105 uint64_t current_index = ser->objects->len;
1106
1107 //first check that node is not yet in objects
1108 gpointer val = g_hash_table_lookup(ser->ref_table, node);
1109 if (val) {
1110 //data is already in table
1111 return;
1112 }
1113 //insert new ref
1114 g_hash_table_insert(ser->ref_table, node, GUINT_TO_POINTER(current_index));
1115
1116 //now append current node to object array
1117 g_ptr_array_add(ser->objects, node);
1118
1119 //now recurse on children
1120 g_node_children_foreach(node, G_TRAVERSE_ALL, serialize_plist, data);
1121 return;
1122}
1123
1124
1125
1126void write_int(GByteArray * bplist, uint64_t val)
1127{
1128 uint64_t size = get_needed_bytes(val);
1129 uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size);
1130 buff[0] = BPLIST_UINT | size >> 1;
1131 memcpy(buff + 1, &val, size);
1132 swap_n_bytes(buff + 1, size);
1133 g_byte_array_append(bplist, buff, sizeof(uint8_t) + size);
1134 free(buff);
1135}
1136
1137void write_real(GByteArray * bplist, double val)
1138{
1139 uint64_t size = get_real_bytes(*((uint64_t *) & val)); //cheat to know used space
1140 uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size);
1141 buff[0] = BPLIST_REAL | size >> 1;
1142 memcpy(buff + 1, &val, size);
1143 swap_n_bytes(buff + 1, size);
1144 g_byte_array_append(bplist, buff, sizeof(uint8_t) + size);
1145 free(buff);
1146}
1147
1148void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size)
1149{
1150 uint8_t marker = mark | (size < 15 ? size : 0xf);
1151 g_byte_array_append(bplist, &marker, sizeof(uint8_t));
1152 if (size >= 15) {
1153 GByteArray *int_buff = g_byte_array_new();
1154 write_int(int_buff, size);
1155 g_byte_array_append(bplist, int_buff->data, int_buff->len);
1156 g_byte_array_free(int_buff, TRUE);
1157 }
1158 uint8_t *buff = (uint8_t *) malloc(size);
1159 memcpy(buff, val, size);
1160 g_byte_array_append(bplist, buff, size);
1161 free(buff);
1162}
1163
1164void write_data(GByteArray * bplist, uint8_t * val, uint64_t size)
1165{
1166 write_raw_data(bplist, BPLIST_DATA, val, size);
1167}
1168
1169void write_string(GByteArray * bplist, char *val)
1170{
1171 uint64_t size = strlen(val);
1172 write_raw_data(bplist, BPLIST_STRING, val, size);
1173}
1174
1175void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size)
1176{
1177 uint64_t size = g_node_n_children(node);
1178 uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf);
1179 g_byte_array_append(bplist, &marker, sizeof(uint8_t));
1180 if (size >= 15) {
1181 GByteArray *int_buff = g_byte_array_new();
1182 write_int(int_buff, size);
1183 g_byte_array_append(bplist, int_buff->data, int_buff->len);
1184 g_byte_array_free(int_buff, TRUE);
1185 }
1186
1187 uint64_t idx = 0;
1188 uint8_t *buff = (uint8_t *) malloc(size * dict_param_size);
1189
1190 GNode *cur = NULL;
1191 int i = 0;
1192 for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) {
1193 idx = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur));
1194 memcpy(buff + i * dict_param_size, &idx, dict_param_size);
1195 swap_n_bytes(buff + i * dict_param_size, dict_param_size);
1196 }
1197
1198 //now append to bplist
1199 g_byte_array_append(bplist, buff, size * dict_param_size);
1200 free(buff);
1201
1202}
1203
1204void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size)
1205{ 230{
1206 uint64_t size = g_node_n_children(node) / 2; 231 return ((struct plist_data *) node->data)->type;
1207 uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf);
1208 g_byte_array_append(bplist, &marker, sizeof(uint8_t));
1209 if (size >= 15) {
1210 GByteArray *int_buff = g_byte_array_new();
1211 write_int(int_buff, size);
1212 g_byte_array_append(bplist, int_buff->data, int_buff->len);
1213 g_byte_array_free(int_buff, TRUE);
1214 }
1215
1216 uint64_t idx1 = 0;
1217 uint64_t idx2 = 0;
1218 uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size);
1219
1220 GNode *cur = NULL;
1221 int i = 0;
1222 for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) {
1223 idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur));
1224 memcpy(buff + i * dict_param_size, &idx1, dict_param_size);
1225 swap_n_bytes(buff + i * dict_param_size, dict_param_size);
1226
1227 idx2 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur->next));
1228 memcpy(buff + (i + size) * dict_param_size, &idx2, dict_param_size);
1229 swap_n_bytes(buff + (i + size) * dict_param_size, dict_param_size);
1230 }
1231
1232 //now append to bplist
1233 g_byte_array_append(bplist, buff, size * dict_param_size);
1234 free(buff);
1235
1236} 232}
1237 233
1238void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) 234uint64_t plist_get_node_uint_val(plist_t node)
1239{ 235{
1240 //first serialize tree 236 if (PLIST_UINT == plist_get_node_type(node))
1241 237 return ((struct plist_data *) node->data)->intval;
1242 //list of objects 238 else
1243 GPtrArray *objects = g_ptr_array_new(); 239 return 0;
1244 //hashtable to write only once same nodes
1245 GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare);
1246
1247 //serialize plist
1248 struct serialize_s ser_s = { objects, ref_table };
1249 g_node_children_foreach(plist, G_TRAVERSE_ALL, serialize_plist, &ser_s);
1250
1251 //now stream to output buffer
1252 uint8_t offset_size = 0; //unknown yet
1253 uint8_t dict_param_size = get_needed_bytes(objects->len);
1254 uint64_t num_objects = objects->len;
1255 uint64_t root_object = 0; //root is first in list
1256 uint64_t offset_table_index = 0; //unknown yet
1257
1258 //setup a dynamic bytes array to store bplist in
1259 GByteArray *bplist_buff = g_byte_array_new();
1260
1261 //set magic number and version
1262 g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE);
1263 g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE);
1264
1265 //write objects and table
1266 int i = 0;
1267 uint8_t *buff = NULL;
1268 uint8_t size = 0;
1269 uint64_t offsets[num_objects];
1270 for (i = 0; i < num_objects; i++) {
1271
1272 offsets[i] = bplist_buff->len;
1273 struct plist_data *data = (struct plist_data *) ((GNode *) g_ptr_array_index(objects, i))->data;
1274
1275 switch (data->type) {
1276 case PLIST_BOOLEAN:
1277 buff = (uint8_t *) malloc(sizeof(uint8_t));
1278 buff[0] = data->boolval ? BPLIST_TRUE : BPLIST_FALSE;
1279 g_byte_array_append(bplist_buff, buff, sizeof(uint8_t));
1280 free(buff);
1281 break;
1282
1283 case PLIST_UINT:
1284 write_int(bplist_buff, data->intval);
1285 break;
1286
1287 case PLIST_REAL:
1288 write_real(bplist_buff, data->realval);
1289 break;
1290
1291 case PLIST_KEY:
1292 case PLIST_STRING:
1293 write_string(bplist_buff, data->strval);
1294 break;
1295 case PLIST_UNICODE:
1296 //TODO
1297 break;
1298 case PLIST_DATA:
1299 write_data(bplist_buff, data->strval, data->length);
1300 case PLIST_ARRAY:
1301 write_array(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size);
1302 break;
1303 case PLIST_DICT:
1304 write_dict(bplist_buff, g_ptr_array_index(objects, i), ref_table, dict_param_size);
1305 break;
1306 case PLIST_DATE:
1307 //TODO
1308 break;
1309 default:
1310 break;
1311 }
1312 }
1313
1314 //write offsets
1315 offset_size = get_needed_bytes(bplist_buff->len);
1316 for (i = 0; i <= num_objects; i++) {
1317 uint8_t *buff = (uint8_t *) malloc(offset_size);
1318 memcpy(buff, offsets + i, offset_size);
1319 swap_n_bytes(buff, offset_size);
1320 g_byte_array_append(bplist_buff, buff, offset_size);
1321 free(buff);
1322 }
1323
1324 //setup trailer
1325 num_objects = bswap_64(num_objects);
1326 root_object = bswap_64(root_object);
1327 offset_table_index = bswap_64(offset_table_index);
1328
1329 char trailer[BPLIST_TRL_SIZE];
1330 memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t));
1331 memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t));
1332 memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t));
1333 memcpy(trailer + BPLIST_TRL_ROOTOBJ_IDX, &root_object, sizeof(uint64_t));
1334 memcpy(trailer + BPLIST_TRL_OFFTAB_IDX, &offset_table_index, sizeof(uint64_t));
1335
1336 g_byte_array_append(bplist_buff, trailer, BPLIST_TRL_SIZE);
1337
1338 //duplicate buffer
1339 *plist_bin = (char *) malloc(bplist_buff->len);
1340 memcpy(*plist_bin, bplist_buff->data, bplist_buff->len);
1341 *length = bplist_buff->len;
1342
1343 g_byte_array_free(bplist_buff, TRUE);
1344} 240}
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 {
47} plist_type; 47} plist_type;
48 48
49 49
50struct plist_data {
51 union {
52 char boolval;
53 uint64_t intval;
54 double realval;
55 char *strval;
56 wchar_t *unicodeval;
57 char *buff;
58 };
59 uint64_t length;
60 plist_type type;
61};
62
63
50 64
51typedef GNode *plist_t; 65typedef GNode *plist_t;
52typedef GNode *dict_t; 66typedef GNode *dict_t;
@@ -67,4 +81,5 @@ void bin_to_plist(const char *plist_bin, uint32_t length, plist_t * plist);
67GNode *find_query_node(plist_t plist, char *key, char *request); 81GNode *find_query_node(plist_t plist, char *key, char *request);
68GNode *find_node(plist_t plist, plist_type type, void *value); 82GNode *find_node(plist_t plist, plist_type type, void *value);
69void get_type_and_value(GNode * node, plist_type * type, void *value); 83void get_type_and_value(GNode * node, plist_type * type, void *value);
84
70#endif 85#endif