summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AFC.c279
-rw-r--r--AFC.h74
-rwxr-xr-xbuildme.sh1
-rw-r--r--iphone.c156
-rw-r--r--iphone.h29
-rw-r--r--lockdown.c349
-rw-r--r--lockdown.h36
-rw-r--r--main.c84
-rw-r--r--main.h1
-rw-r--r--plist.c91
-rw-r--r--plist.h17
-rw-r--r--usbmux.c198
-rw-r--r--usbmux.h39
13 files changed, 1354 insertions, 0 deletions
diff --git a/AFC.c b/AFC.c
new file mode 100644
index 0000000..29c0f97
--- /dev/null
+++ b/AFC.c
@@ -0,0 +1,279 @@
1/*
2 * AFC.c -- contains functions for the built-in AFC client.
3 * Written by FxChiP
4 */
5
6#include "AFC.h"
7
8extern int debug;
9
10AFClient *afc_connect(iPhone *phone, int s_port, int d_port) {
11 if (!phone) return NULL;
12 AFClient *client = (AFClient*)malloc(sizeof(AFClient));
13 client->connection = mux_connect(phone, s_port, d_port);
14 if (!client->connection) { free(client); return NULL; }
15 else {
16 client->afc_packet = (AFCPacket*)malloc(sizeof(AFCPacket));
17 if (client->afc_packet) {
18 client->phone = phone;
19 client->afc_packet->packet_num = 0;
20 client->afc_packet->unknown1 = client->afc_packet->unknown2 = client->afc_packet->unknown3 = client->afc_packet->unknown4 = 0;
21 client->afc_packet->header1 = 0x36414643;
22 client->afc_packet->header2 = 0x4141504C;
23 client->file_handle = 0;
24 return client;
25 } else {
26 mux_close_connection(client->phone, client->connection);
27 free(client);
28 return NULL;
29 }
30 }
31
32 return NULL; // should never get to this point
33}
34
35void afc_disconnect(AFClient *client) {
36 // client and its members should never be NULL is assumed here.
37 if (!client || !client->connection || !client->phone || !client->afc_packet) return;
38 mux_close_connection(client->phone, client->connection);
39 free(client->afc_packet);
40 free(client);
41}
42
43int count_nullspaces(char *string, int number) {
44 int i = 0, nulls = 0;
45 for (i = 0; i < number; i++) {
46 if (string[i] == '\0') nulls++;
47 }
48 return nulls;
49}
50
51int dispatch_AFC_packet(AFClient *client, char *data, int length) {
52 char *buffer;
53 int bytes = 0;
54 if (!client || !client->connection || !client->phone || !client->afc_packet) return 0;
55 if (!data || !length) length = 0;
56
57 client->afc_packet->packet_num++;
58 client->afc_packet->entire_length = client->afc_packet->this_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket);
59
60 if (!length) {
61 bytes = mux_send(client->phone, client->connection, (char*)client->afc_packet, client->afc_packet->this_length);
62 if (bytes <= 0) return 0;
63 else return bytes;
64 } else {
65 buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length);
66 memcpy(buffer, client->afc_packet, sizeof(AFCPacket));
67 memcpy(buffer+sizeof(AFCPacket), data, length);
68 buffer[client->afc_packet->this_length-1] = '\0';
69
70 bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length);
71 free(buffer); // don't need it
72 if (bytes <= 0) return 0;
73 else return bytes;
74 }
75
76 return 0;
77}
78
79int receive_AFC_data(AFClient *client, char **dump_here) {
80 AFCPacket *r_packet;
81 char *buffer = (char*)malloc(sizeof(AFCPacket) * 4);
82 int bytes = 0, recv_len = 0;
83
84 bytes = mux_recv(client->phone, client->connection, buffer, sizeof(AFCPacket) * 4);
85 if (bytes <= 0) {
86 free(buffer);
87 printf("Just didn't get enough.\n");
88 *dump_here = NULL;
89 return 0;
90 }
91
92 r_packet = (AFCPacket*)malloc(sizeof(AFCPacket));
93 memcpy(r_packet, buffer, sizeof(AFCPacket));
94
95 if (r_packet->entire_length == r_packet->this_length && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) {
96 *dump_here = (char*)malloc(sizeof(char) * (r_packet->entire_length-sizeof(AFCPacket)));
97 memcpy(*dump_here, buffer+sizeof(AFCPacket), r_packet->entire_length-sizeof(AFCPacket));
98 free(buffer);
99 free(r_packet);
100 return r_packet->entire_length - sizeof(AFCPacket);
101 }
102
103 uint32 param1 = buffer[sizeof(AFCPacket)];
104 free(buffer);
105
106 if (r_packet->operation == 0x01) {
107 printf("Oops? Bad operation code received.\n");
108 if (param1 == 0) printf("... false alarm, but still\n");
109 else printf("Errno %i\n", param1);
110 free(r_packet);
111 *dump_here = NULL;
112 return 0;
113 } else {
114 printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length);
115 }
116
117 recv_len = r_packet->entire_length - r_packet->this_length;
118 free(r_packet);
119 buffer = (char*)malloc(sizeof(char) * recv_len);
120 bytes = mux_recv(client->phone, client->connection, buffer, recv_len);
121 if (bytes <= 0) {
122 free(buffer);
123 printf("Didn't get it at the second pass.\n");
124 *dump_here = NULL;
125 return 0;
126 }
127
128 *dump_here = buffer; // what they do beyond this point = not my problem
129 return bytes;
130}
131
132char **afc_get_dir_list(AFClient *client, char *dir) {
133 client->afc_packet->operation = AFC_LIST_DIR;
134 int bytes = 0;
135 char *blah = NULL, **list = NULL;
136 bytes = dispatch_AFC_packet(client, dir, strlen(dir));
137 if (!bytes) return NULL;
138
139 bytes = receive_AFC_data(client, &blah);
140 if (!bytes && !blah) return NULL;
141
142 list = make_strings_list(blah, bytes);
143 free(blah);
144 return list;
145}
146
147char **make_strings_list(char *tokens, int true_length) {
148 if (!tokens || !true_length) return NULL;
149 int nulls = 0, i = 0, j = 0;
150 char **list = NULL;
151
152 nulls = count_nullspaces(tokens, true_length);
153 list = (char**)malloc(sizeof(char*) * (nulls + 1));
154 for (i = 0; i < nulls; i++) {
155 list[i] = strdup(tokens+j);
156 j += strlen(list[i]) + 1;
157 }
158 list[i] = strdup("");
159 return list;
160}
161
162AFCFile *afc_get_file_info(AFClient *client, char *path) {
163 client->afc_packet->operation = AFC_GET_INFO;
164 dispatch_AFC_packet(client, path, strlen(path));
165
166 char *received, **list;
167 AFCFile *my_file;
168 int length, i = 0;
169
170 length = receive_AFC_data(client, &received);
171 list = make_strings_list(received, length);
172 free(received);
173 if (list) {
174 my_file = (AFCFile *)malloc(sizeof(AFCFile));
175 for (i = 0; strcmp(list[i], ""); i++) {
176 if (!strcmp(list[i], "st_size")) {
177 my_file->size = atoi(list[i+1]);
178 }
179
180
181 if (!strcmp(list[i], "st_blocks")) {
182 my_file->blocks = atoi(list[i+1]);
183 }
184
185 if (!strcmp(list[i], "st_ifmt")) {
186 if (!strcmp(list[i+1], "S_IFREG")) {
187 my_file->type = S_IFREG;
188 } else if (!strcmp(list[i+1], "S_IFDIR")) {
189 my_file->type = S_IFDIR;
190 }
191 }
192 }
193 free_dictionary(list);
194 return my_file;
195 } else {
196 return NULL;
197 }
198}
199
200AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) {
201 if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL;
202 if (!client ||!client->connection || !client->phone ||!client->afc_packet) return NULL;
203 char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1));
204 AFCFile *file_infos = NULL;
205 memcpy(further_data, &file_mode, 4);
206 uint32 ag = 0;
207 memcpy(further_data+4, &ag, 4);
208 memcpy(further_data+8, filename, strlen(filename));
209 further_data[8+strlen(filename)] = '\0';
210 int bytes = 0, length_thing = 0;
211 client->afc_packet->operation = AFC_FILE_OPEN;
212
213 bytes = dispatch_AFC_packet(client, further_data, 8+strlen(filename));
214 free(further_data);
215 if (bytes <= 0) {
216 printf("didn't read enough\n");
217 return NULL;
218 } else {
219 printf("O HAI\n");
220 length_thing = receive_AFC_data(client, &further_data);
221 if (length_thing && further_data) {
222 printf("ARA\n");
223 file_infos = afc_get_file_info(client, filename);
224 memcpy(&file_infos->filehandle, further_data, 4);
225 printf("gr\n");
226 return file_infos;
227 } else {
228 printf("didn't get further data or something\n");
229 return NULL;
230 }
231 }
232 printf("what the fuck\n");
233 return NULL;
234}
235
236int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) {
237 if (!client || !client->afc_packet || !client->phone || !client->connection || !file) return -1;
238 AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket));
239 char *input = NULL;
240 packet->unknown1 = packet->unknown2 = 0;
241 packet->filehandle = file->filehandle;
242 packet->size = length;
243 int bytes = 0;
244
245 client->afc_packet->operation = AFC_READ;
246 bytes = dispatch_AFC_packet(client, packet, sizeof(AFCFilePacket));
247
248 if (bytes > 0) {
249 bytes = receive_AFC_data(client, &input);
250 if (bytes <= 0) {
251 return -1;
252 } else {
253 memcpy(data, input, (bytes > length) ? length : bytes);
254 return (bytes > length) ? length : bytes;
255 }
256 } else {
257 return -1;
258 }
259 return 0;
260}
261
262void afc_close_file(AFClient *client, AFCFile *file) {
263 char *buffer = malloc(sizeof(char) * 8);
264 uint32 zero = 0;
265 if (debug) printf("File handle %i\n", file->filehandle);
266 memcpy(buffer, &file->filehandle, sizeof(uint32));
267 memcpy(buffer, &zero, sizeof(zero));
268 client->afc_packet->operation = AFC_FILE_CLOSE;
269 int bytes = 0;
270 bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8);
271 free(buffer);
272 if (!bytes) return;
273
274 bytes = receive_AFC_data(client, &buffer);
275 if (bytes<=0 && !buffer) printf("closefile: all went as expected\n");
276 else { printf("We have a buffer!??!?\nLength %i\n", bytes); fwrite(buffer, 1, bytes, stdout); printf("\n"); }
277 if (buffer) free(buffer); // we're *SUPPOSED* to get an "error" here.
278}
279
diff --git a/AFC.h b/AFC.h
new file mode 100644
index 0000000..281e624
--- /dev/null
+++ b/AFC.h
@@ -0,0 +1,74 @@
1/*
2 * AFC.h
3 * Defines and structs and the like for the built-in AFC client
4 * Written by FxChiP
5 */
6
7#include "usbmux.h"
8#include "iphone.h"
9
10#include <string.h>
11#include <stdio.h>
12#include <stdlib.h>
13
14typedef struct {
15 //const uint32 header1 = 0x36414643; // '6AFC' or 'CFA6' when sent ;)
16 uint32 header1, header2;
17 //const uint32 header2 = 0x4141504C; // 'AAPL' or 'LPAA' when sent ;)
18 uint32 entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4;
19} AFCPacket;
20
21typedef struct {
22 usbmux_tcp_header *connection;
23 iPhone *phone;
24 AFCPacket *afc_packet;
25 int file_handle;
26} AFClient;
27
28typedef struct {
29 uint32 filehandle, unknown1, size, unknown2;
30} AFCFilePacket;
31
32typedef struct {
33 uint32 filehandle, blocks, size, type;
34} AFCFile;
35
36typedef struct __AFCToken {
37 struct __AFCToken *last, *next;
38 char *token;
39} AFCToken;
40
41enum {
42 S_IFREG = 0,
43 S_IFDIR = 1
44};
45
46enum {
47 AFC_FILE_READ = 0x00000002,
48 AFC_FILE_WRITE = 0x00000003
49};
50
51enum {
52 AFC_ERROR = 0x00000001,
53 AFC_GET_INFO = 0x0000000a,
54 AFC_GET_DEVINFO = 0x0000000b,
55 AFC_LIST_DIR = 0x00000003,
56 AFC_SUCCESS_RESPONSE = 0x00000002,
57 AFC_FILE_OPEN = 0x0000000d,
58 AFC_FILE_CLOSE = 0x00000014,
59 AFC_FILE_HANDLE = 0x0000000e,
60 AFC_READ = 0x0000000f
61};
62
63AFClient *afc_connect(iPhone *phone, int s_port, int d_port);
64void afc_disconnect(AFClient *client);
65int count_nullspaces(char *string, int number);
66char **make_strings_list(char *tokens, int true_length);
67int dispatch_AFC_packet(AFClient *client, char *data, int length);
68int receive_AFC_data(AFClient *client, char **dump_here);
69
70char **afc_get_dir_list(AFClient *client, char *dir);
71AFCFile *afc_get_file_info(AFClient *client, char *path);
72AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode);
73void afc_close_file(AFClient *client, AFCFile *file);
74int afc_read_file(AFClient *client, AFCFile *file, char *data, int length);
diff --git a/buildme.sh b/buildme.sh
new file mode 100755
index 0000000..75549ba
--- /dev/null
+++ b/buildme.sh
@@ -0,0 +1 @@
gcc `xml2-config --cflags --libs` -o main usbmux.c main.c iphone.c plist.c lockdown.c AFC.c -lusb -lgnutls
diff --git a/iphone.c b/iphone.c
new file mode 100644
index 0000000..4ddb571
--- /dev/null
+++ b/iphone.c
@@ -0,0 +1,156 @@
1/* iPhone.c
2 * Functions for creating and initializing iPhone structures
3 */
4
5#include "usbmux.h"
6#include "iphone.h"
7#include <usb.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12/* get_iPhone()
13 *
14 * Returns a structure with data on the first iPhone it finds.
15 * (Or NULL, on error)
16 */
17extern int debug;
18
19iPhone *get_iPhone() {
20 iPhone *phone = (iPhone*)malloc(sizeof(iPhone));
21 usbmux_version_header *version = version_header();
22
23 // initialize the struct
24 phone->device = NULL;
25 phone->__device = NULL;
26
27 // Initialize libusb.
28 usb_init();
29 usb_find_busses();
30 usb_find_devices();
31 struct usb_bus *busses = usb_get_busses(), *bus;
32 struct usb_device *dev;
33
34 for (bus = busses; bus; bus = bus->next) {
35 for (dev = bus->devices; dev; dev = dev->next) {
36 if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) {
37 phone->__device = dev;
38 phone->device = usb_open(phone->__device);
39 usb_reset(phone->device);
40 }
41 }
42 }
43
44 phone->device = NULL; // :( sorry Daniel
45 phone->__device = NULL; // :( sorry Daniel
46
47 for (bus = busses; bus; bus = bus->next) { // do it again as per libusb documentation
48 for (dev = bus->devices; dev; dev = dev->next) {
49 if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) {
50 phone->__device = dev;
51 phone->device = usb_open(phone->__device);
52 usb_set_configuration(phone->device, 3);
53 usb_claim_interface(phone->device, 1);
54 break;
55 }
56 }
57 if (phone->__device && phone->device) break;
58 }
59
60 if (!phone->device || !phone->__device) { // nothing connected
61 free_iPhone(phone);
62 if (debug) printf("get_iPhone(): iPhone not found\n");
63 return NULL;
64 }
65
66 // Okay, initialize the phone now.
67 int bytes = 0;
68 bytes = usb_bulk_write(phone->device, BULKOUT, (char*)version, sizeof(*version), 800);
69 if (bytes < 20 && debug) {
70 printf("get_iPhone(): libusb did NOT send enough!\n");
71 if (bytes < 0) {
72 printf("get_iPhone(): libusb gave me the error: %s\n", usb_strerror());
73 }
74 }
75 bytes = usb_bulk_read(phone->device, BULKIN, (char*)version, sizeof(*version), 800);
76 if (bytes < 20) {
77 free_iPhone(phone);
78 if (debug) printf("get_iPhone(): Invalid version message -- header too short.\n");
79 if (debug && bytes < 0) printf("get_iPhone(): libusb error message: %s\n", usb_strerror());
80 return NULL;
81 } else {
82 if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) {
83 // We're all ready to roll.
84 printf("get_iPhone() success\n");
85 return phone;
86 } else { // BAD HEADER
87 free_iPhone(phone);
88 if (debug) printf("get_iPhone(): Received a bad header/invalid version number.");
89 return NULL;
90 }
91 }
92
93 if (debug) printf("get_iPhone(): Unknown error.\n");
94 return NULL; // if it got to this point it's gotta be bad
95}
96
97/* free_iPhone(victim)
98 * This is a library-level function; deals directly with the iPhone to tear down relations,
99 * but otherwise is mostly internal.
100 *
101 * victim: a pointer to an iPhone structure
102 * Cleans up an iPhone structure, then frees the structure itself.
103 */
104
105void free_iPhone(iPhone *victim) {
106 if (victim->buffer) free(victim->buffer);
107 if (victim->device) {
108 usb_release_interface(victim->device, 1);
109 usb_reset(victim->device);
110 usb_close(victim->device);
111 }
112 free(victim);
113}
114
115/* send_to_phone(phone, data, datalen)
116 * This is a low-level (i.e. directly to phone) function.
117 *
118 * phone: the iPhone to send data to
119 * data: the data to send to the iPhone
120 * datalen: the length of the data
121 *
122 * Returns the number of bytes sent, or -1 on error or something.
123 */
124int send_to_phone(iPhone *phone, char *data, int datalen) {
125 if (!phone) return -1;
126 int bytes = 0;
127 // it may die here
128 if (debug) printf("dying here?\ndatalen = %i\ndata = %x\n", datalen, data);
129
130 bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, 800);
131 if (debug) printf("noooo...?\n");
132 if (bytes < datalen) {
133 return -1;
134 } else {
135 return bytes;
136 }
137
138 return -1;
139}
140
141/* recv_from_phone(phone, data, datalen):
142 * This function is a low-level (i.e. direct to iPhone) function.
143 *
144 * phone: the iPhone to receive data from
145 * data: where to put data read
146 * datalen: how much data to read in
147 *
148 * Returns: how many bytes were read in, or -1 on error.
149 */
150int recv_from_phone(iPhone *phone, char *data, int datalen) {
151 if (!phone) return -1;
152 int bytes = 0;
153 bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500);
154 return bytes;
155}
156
diff --git a/iphone.h b/iphone.h
new file mode 100644
index 0000000..a49b7ef
--- /dev/null
+++ b/iphone.h
@@ -0,0 +1,29 @@
1/* iphone.h
2 * iPhone struct
3 * Written by FxChiP */
4
5#ifndef IPHONE_H
6#define IPHONE_H
7
8#ifndef USBMUX_H
9#include "usbmux.h"
10#warning usbmux not included?
11#endif
12
13#include <usb.h>
14
15#define BULKIN 0x85
16#define BULKOUT 0x04
17
18typedef struct {
19 char *buffer;
20 struct usb_dev_handle *device;
21 struct usb_device *__device;
22} iPhone;
23
24// Function definitions
25void free_iPhone(iPhone *victim);
26iPhone *get_iPhone();
27int send_to_phone(iPhone *phone, char *data, int datalen);
28int recv_from_phone(iPhone *phone, char *data, int datalen);
29#endif
diff --git a/lockdown.c b/lockdown.c
new file mode 100644
index 0000000..5ca6001
--- /dev/null
+++ b/lockdown.c
@@ -0,0 +1,349 @@
1/*
2 * lockdown.c -- libiphone built-in lockdownd client
3 * Written by FxChiP
4 */
5
6#include "usbmux.h"
7#include "iphone.h"
8#include "lockdown.h"
9#include <errno.h>
10#include <string.h>
11
12extern int debug;
13
14lockdownd_client *new_lockdownd_client(iPhone *phone) {
15 if (!phone) return NULL;
16 lockdownd_client *control = (lockdownd_client*)malloc(sizeof(lockdownd_client));
17 control->connection = mux_connect(phone, 0x0a00, 0xf27e);
18 if (!control->connection) {
19 free(control);
20 return NULL;
21 }
22
23 control->ssl_session = (gnutls_session_t*)malloc(sizeof(gnutls_session_t));
24 control->in_SSL = 0;
25 control->iphone = phone;
26 control->gtls_buffer_hack_len = 0;
27 return control;
28}
29
30void lockdown_close(lockdownd_client *control) {
31 if (!control) return;
32 if (control->connection) {
33 mux_close_connection(control->iphone, control->connection);
34 }
35
36 if (control->ssl_session) free(control->ssl_session);
37 free(control);
38}
39
40
41int lockdownd_recv(lockdownd_client *control, char **dump_data) {
42 char *receive;
43 uint32 datalen = 0, bytes = 0;
44
45 if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, &datalen, sizeof(datalen));
46 else bytes = gnutls_record_recv(*control->ssl_session, &datalen, sizeof(datalen));
47 datalen = ntohl(datalen);
48
49 receive = (char*)malloc(sizeof(char) * datalen);
50 if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, receive, datalen);
51 else bytes = gnutls_record_recv(*control->ssl_session, receive, datalen);
52 *dump_data = receive;
53 return bytes;
54}
55
56int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length) {
57 char *real_query;
58 int bytes;
59
60 real_query = (char*)malloc(sizeof(char) * (length+4));
61 length = htonl(length);
62 memcpy(real_query, &length, sizeof(length));
63 memcpy(real_query+4, raw_data, ntohl(length));
64 if (!control->in_SSL) bytes = mux_send(control->iphone, control->connection, real_query, ntohl(length)+sizeof(length));
65 else gnutls_record_send(*control->ssl_session, real_query, ntohl(length)+sizeof(length));
66 return bytes;
67}
68
69int lockdownd_hello(lockdownd_client *control) {
70 xmlDocPtr plist = new_plist();
71 xmlNode *dict, *key;
72 char **dictionary;
73 int bytes = 0, i = 0;
74
75 dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
76 key = add_key_str_dict_element(plist, dict, "Request", "QueryType", 1);
77 char *XML_content;
78 uint32 length;
79
80 xmlDocDumpMemory(plist, &XML_content, &length);
81
82 bytes = lockdownd_send(control, XML_content, length);
83
84 xmlFree(XML_content);
85 xmlFreeDoc(plist); plist = NULL;
86
87 bytes = lockdownd_recv(control, &XML_content);
88
89 plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0);
90 if (!plist) return 0;
91 dict = xmlDocGetRootElement(plist);
92 for (dict = dict->children; dict; dict = dict->next) {
93 if (!xmlStrcmp(dict->name, "dict")) break;
94 }
95 if (!dict) return 0;
96
97 dictionary = read_dict_element_strings(dict);
98 xmlFreeDoc(plist);
99 free(XML_content);
100
101 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
102 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) {
103 free_dictionary(dictionary);
104 return 1;
105 }
106 }
107
108 free_dictionary(dictionary);
109 return 0;
110}
111
112int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID) {
113 xmlDocPtr plist = new_plist();
114 xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
115 xmlNode *key;
116 char *what2send = NULL, **dictionary = NULL;
117 uint32 len = 0, bytes = 0, return_me = 0, i = 0;
118 // end variables
119
120 key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1);
121 if (!key) {
122 if (debug) printf("Couldn't add a key.\n");
123 xmlFreeDoc(plist);
124 return 0;
125 }
126 key = add_key_str_dict_element(plist, dict, "Request", "StartSession", 1);
127 if (!key) {
128 if (debug) printf("Couldn't add a key.\n");
129 xmlFreeDoc(plist);
130 return 0;
131 }
132
133 xmlDocDumpMemory(plist, &what2send, &len);
134 bytes = lockdownd_send(control, what2send, len);
135
136 xmlFree(what2send);
137 xmlFreeDoc(plist);
138
139 if (bytes > 0) {
140 len = lockdownd_recv(control, &what2send);
141 plist = xmlReadMemory(what2send, len, NULL, NULL, 0);
142 dict = xmlDocGetRootElement(plist);
143 for (dict = dict->children; dict; dict = dict->next) {
144 if (!xmlStrcmp(dict->name, "dict")) break;
145 }
146 dictionary = read_dict_element_strings(dict);
147 xmlFreeDoc(plist);
148 free(what2send);
149 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
150 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) {
151 // Set up GnuTLS...
152 gnutls_certificate_credentials_t xcred;
153
154 if (debug) printf("We started the session OK, now trying GnuTLS\n");
155 errno = 0;
156 gnutls_global_init();
157 gnutls_certificate_allocate_credentials(&xcred);
158 gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM);
159 gnutls_init(control->ssl_session, GNUTLS_CLIENT);
160 if ((return_me = gnutls_priority_set_direct(*control->ssl_session, "NORMAL:+VERS-SSL3.0", NULL)) < 0) {
161 printf("oops? bad options?\n");
162 gnutls_perror(return_me);
163 return 0;
164 }
165 gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me.
166
167 if (debug) printf("GnuTLS step 1...\n");
168 gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control);
169 if (debug) printf("GnuTLS step 2...\n");
170 gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func)&lockdownd_secuwrite);
171 if (debug) printf("GnuTLS step 3...\n");
172 gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func)&lockdownd_securead);
173 if (debug) printf("GnuTLS step 4 -- now handshaking...\n");
174
175 if (errno && debug) printf("WARN: errno says %s before handshake!\n", strerror(errno));
176 return_me = gnutls_handshake(*control->ssl_session);
177 if (debug) printf("GnuTLS handshake done...\n");
178
179 free_dictionary(dictionary);
180
181 if (return_me != GNUTLS_E_SUCCESS) {
182 if (debug) printf("GnuTLS reported something wrong.\n");
183 gnutls_perror(return_me);
184 if (debug) printf("oh.. errno says %s\n", strerror(errno));
185 return 0;
186 } else {
187 control->in_SSL = 1;
188 return 1;
189 }
190 }
191 }
192
193 if (debug) {
194 printf("Apparently failed negotiating with lockdownd.\n");
195 printf("Responding dictionary: \n");
196 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
197 printf("\t%s: %s\n", dictionary[i], dictionary[i+1]);
198 }
199 }
200
201 free_dictionary(dictionary);
202 return 0;
203 } else {
204 if (debug) printf("Didn't get enough bytes.\n");
205 return 0;
206 }
207}
208
209ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) {
210 int bytes = 0;
211 lockdownd_client *control;
212 control = (lockdownd_client*)transport;
213 if (debug) printf("lockdownd_secuwrite() called\n");
214 if (debug) printf("pre-send\nlength = %i\n", length);
215 bytes = mux_send(control->iphone, control->connection, buffer, length);
216 if (debug) printf("post-send\nsent %i bytes\n", bytes);
217 return bytes;
218}
219
220ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) {
221 int bytes = 0, pos_start_fill = 0;
222 char *hackhackhack = NULL;
223 lockdownd_client *control;
224 control = (lockdownd_client*)transport;
225 if (debug) printf("lockdownd_securead() called\nlength = %i\n", length);
226 // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more.
227 if (control->gtls_buffer_hack_len > 0) {
228 if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got
229 length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length
230 pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at
231 memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially
232 free(control->gtls_buffer_hack); // free our memory, it's not chained anymore
233 control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore
234 if (debug) printf("Did a partial fill to help quench thirst for data\n");
235 } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less...
236 control->gtls_buffer_hack_len -= length; // subtract what they're asking for
237 memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer
238 hackhackhack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer.
239 memcpy(hackhackhack, control->gtls_buffer_hack+length, control->gtls_buffer_hack_len); // Move what's left into the new one
240 free(control->gtls_buffer_hack); // Free the old one
241 control->gtls_buffer_hack = hackhackhack; // And make it the new one.
242 hackhackhack = NULL;
243 if (debug) printf("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len);
244 return length; // hand it over.
245 } else { // length == hack length
246 memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs
247 free(control->gtls_buffer_hack); // free our "obligation"
248 control->gtls_buffer_hack_len = 0; // free our "obligation"
249 if (debug) printf("Satiated the thirst for data; now we have to eventually receive again.\n");
250 return length; // hand it over
251 }
252 }
253 // End buffering hack!
254 char *recv_buffer = (char*)malloc(sizeof(char) * (length * 400)); // ensuring nothing stupid happens
255
256 if (debug) printf("pre-read\nclient wants %i bytes\n", length);
257 bytes = mux_recv(control->iphone, control->connection, recv_buffer, (length * 400));
258 if (debug) printf("post-read\nwe got %i bytes\n", bytes);
259 if (bytes >= length) {
260 if (bytes > length) {
261 if (debug) printf("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n");
262 if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet
263 //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution!
264 control->gtls_buffer_hack_len += bytes-length;
265 control->gtls_buffer_hack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len);
266 memcpy(control->gtls_buffer_hack, recv_buffer+length, control->gtls_buffer_hack_len);
267 } else { // if there is.
268 control->gtls_buffer_hack = realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length));
269 memcpy(control->gtls_buffer_hack+control->gtls_buffer_hack_len, recv_buffer+length, bytes-length);
270 control->gtls_buffer_hack_len += bytes - length;
271 }
272 }
273 memcpy(buffer+pos_start_fill, recv_buffer, length);
274 free(recv_buffer);
275 if (bytes == length) { if (debug) printf("Returning how much we received.\n"); return bytes; }
276 else { if (debug) printf("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len); return length; }
277 }
278 return bytes;
279}
280
281int lockdownd_start_service(lockdownd_client *control, const char *service) {
282 if (!control) return 0;
283 if (!control->in_SSL && !lockdownd_start_SSL_session(control, "29942970-207913891623273984")) return 0;
284
285 char *XML_query, **dictionary;
286 uint32 length, i = 0, port = 0;
287 uint8 result = 0;
288
289 xmlDocPtr plist = new_plist();
290 xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
291 xmlNode *key;
292 key = add_key_str_dict_element(plist, dict, "Request", "StartService", 1);
293 if (!key) { xmlFreeDoc(plist); return 0; }
294 key = add_key_str_dict_element(plist, dict, "Service", service, 1);
295 if (!key) { xmlFreeDoc(plist); return 0; }
296
297 xmlDocDumpMemory(plist, &XML_query, &length);
298
299 lockdownd_send(control, XML_query, length);
300 free(XML_query);
301
302 length = lockdownd_recv(control, &XML_query);
303
304 xmlFreeDoc(plist);
305
306 if (length <= 0) return 0;
307 else {
308 plist = xmlReadMemory(XML_query, length, NULL, NULL, 0);
309 if (!plist) return 0;
310 dict = xmlDocGetRootElement(plist);
311 if (!dict) return 0;
312 for (dict = dict->children; dict; dict = dict->next) {
313 if (!xmlStrcmp(dict->name, "dict")) break;
314 }
315
316 if (!dict) return 0;
317 dictionary = read_dict_element_strings(dict);
318
319 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
320 if (debug) printf("lockdownd_start_service() dictionary %s: %s\n", dictionary[i], dictionary[i+1]);
321
322 if (!xmlStrcmp(dictionary[i], "Port")) {
323 port = atoi(dictionary[i+1]);
324 if (debug) printf("lockdownd_start_service() atoi'd port: %i\n", port);
325 }
326
327 if (!xmlStrcmp(dictionary[i], "Result")) {
328 if (!xmlStrcmp(dictionary[i+1], "Success")) {
329 result = 1;
330 }
331 }
332 }
333
334 if (debug) {
335 printf("lockdownd_start_service(): DATA RECEIVED:\n\n");
336 fwrite(XML_query, 1, length, stdout);
337 printf("end data received by lockdownd_start_service()\n");
338 }
339
340 free(XML_query);
341 xmlFreeDoc(plist);
342 free_dictionary(dictionary);
343 if (port && result) return port;
344 else return 0;
345 }
346
347 return 0;
348}
349
diff --git a/lockdown.h b/lockdown.h
new file mode 100644
index 0000000..0acd624
--- /dev/null
+++ b/lockdown.h
@@ -0,0 +1,36 @@
1/*
2 * lockdown.h
3 * Defines lockdown stuff, like the client struct.
4 */
5
6#ifndef LOCKDOWND_H
7#define LOCKDOWND_H
8
9#include "plist.h"
10
11#include <gnutls/gnutls.h>
12#include <string.h>
13
14typedef struct {
15 usbmux_tcp_header *connection;
16 gnutls_session_t *ssl_session;
17 iPhone *iphone;
18 int in_SSL;
19 char *gtls_buffer_hack;
20 int gtls_buffer_hack_len;
21} lockdownd_client;
22
23lockdownd_client *new_lockdownd_client(iPhone *phone);
24int lockdownd_hello(lockdownd_client *control);
25int lockdownd_recv(lockdownd_client *control, char **dump_data);
26int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length);
27void lockdownd_close(lockdownd_client *control);
28
29// SSL functions
30int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID);
31ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length);
32ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length);
33
34// Higher-level lockdownd stuff
35int lockdownd_start_service(lockdownd_client *control, const char *service);
36#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..4cde3d9
--- /dev/null
+++ b/main.c
@@ -0,0 +1,84 @@
1/*
2 * libiphone main.c written by FxChiP
3 * With much help from Daniel Brownlees
4 */
5
6#include <stdio.h>
7#include <string.h>
8#include <errno.h>
9#include <usb.h>
10
11#include "usbmux.h"
12#include "iphone.h"
13
14#include <libxml/parser.h>
15#include <libxml/tree.h>
16#include "plist.h"
17#include "lockdown.h"
18#include "AFC.h"
19
20int debug = 1;
21
22int main(int argc, char *argv[]) {
23 iPhone *phone = get_iPhone();
24 if (argc > 1 && !strcasecmp(argv[1], "--debug")) debug = 1;
25 else debug = 0;
26 char *response = (char*)malloc(sizeof(char) * 2048);
27 int bytes = 0, port = 0, i = 0;
28 if (phone) printf("I got a phone.\n");
29 else { printf("oops\n"); return -1; }
30
31 lockdownd_client *control = new_lockdownd_client(phone);
32 if (!lockdownd_hello(control)) {
33 printf("Something went wrong in the lockdownd client, go take a look.\n");
34 } else {
35 printf("We said hello. :)\n");
36 }
37
38 printf("Now starting SSL.\n");
39 if (!lockdownd_start_SSL_session(control, "29942970-207913891623273984")) {
40 printf("Error happened in GnuTLS...\n");
41 } else {
42 printf("... we're in SSL with the phone... !?\n");
43 }
44 port = lockdownd_start_service(control, "com.apple.afc");
45 if (port) {
46 printf("Start Service successful -- connect on port %i\n", port);
47 AFClient *afc = afc_connect(phone, 3432, port);
48 if (afc) {
49 char **dirs;
50 dirs = afc_get_dir_list(afc, "/eafaedf");
51 if (!dirs) dirs = afc_get_dir_list(afc, "/");
52 printf("Directory time.\n");
53 for (i = 0; strcmp(dirs[i], ""); i++) {
54 printf("/%s\n", dirs[i]);
55 }
56
57 free_dictionary(dirs);
58 AFCFile *my_file = afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", AFC_FILE_READ);
59 if (my_file) {
60 printf("A file size: %i\n", my_file->size);
61 char *file_data = (char*)malloc(sizeof(char) * my_file->size);
62 bytes = afc_read_file(afc, my_file, file_data, my_file->size);
63 if (bytes >= 0) {
64 printf("The file's data:\n");
65 fwrite(file_data, 1, bytes, stdout);
66 }
67 printf("\nClosing my file.\n");
68 afc_close_file(afc, my_file);
69 free(my_file);
70 free(file_data);
71 } else printf("couldn't open a file\n");
72 }
73 afc_disconnect(afc);
74 } else {
75 printf("Start service failure.\n");
76 }
77
78 printf("All done.\n");
79
80 free_iPhone(phone);
81
82 return 0;
83}
84
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/main.h
@@ -0,0 +1 @@
diff --git a/plist.c b/plist.c
new file mode 100644
index 0000000..cbd6302
--- /dev/null
+++ b/plist.c
@@ -0,0 +1,91 @@
1/*
2 * plist.c
3 * Builds plist XML structures.
4 * Written by FxChiP
5 */
6
7#include <libxml/parser.h>
8#include <libxml/tree.h>
9#include <string.h>
10#include "plist.h"
11
12const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
13<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
14<plist version=\"1.0\">\n\
15</plist>\0";
16
17xmlDocPtr new_plist() {
18 char *plist = strdup(plist_base);
19 xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0);
20 if (!plist_xml) return NULL;
21 free(plist);
22 return plist_xml;
23}
24
25void free_plist(xmlDocPtr plist) {
26 if (!plist) return;
27 xmlFreeDoc(plist);
28}
29
30xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth) {
31 if (!plist) return NULL;
32 int i = 0;
33 xmlNode *child;
34 if (!to_node) to_node = xmlDocGetRootElement(plist);
35 for (i = 0; i < depth; i++) {
36 xmlNodeAddContent(to_node, "\t");
37 }
38 child = xmlNewChild(to_node, NULL, name, content);
39 xmlNodeAddContent(to_node, "\n");
40 return child;
41}
42
43xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth) {
44 xmlNode *keyPtr;
45 keyPtr = add_child_to_plist(plist, "key", key, dict, depth);
46 add_child_to_plist(plist, "string", value, dict, depth);
47 return keyPtr;
48}
49
50char **read_dict_element_strings(xmlNode *dict) {
51 // reads a set of keys and strings into an array where each even number is a key and odd numbers are values.
52 // if the odd number is \0, that's the end of the list.
53 char **return_me = NULL, **old = NULL;
54 int current_length = 0;
55 int current_pos = 0;
56 xmlNode *dict_walker;
57
58 for (dict_walker = dict->children; dict_walker; dict_walker = dict_walker->next) {
59 if (!xmlStrcmp(dict_walker->name, "key")) {
60 current_length += 2;
61 old = return_me;
62 return_me = realloc(return_me, sizeof(char*) * current_length);
63 if (!return_me) {
64 free(old);
65 return NULL;
66 }
67 return_me[current_pos++] = xmlNodeGetContent(dict_walker);
68 return_me[current_pos++] = xmlNodeGetContent(dict_walker->next->next);
69 }
70 }
71
72 // one last thing...
73 old = return_me;
74 return_me = realloc(return_me, sizeof(char*) * current_length+1);
75 return_me[current_pos] = strdup("");
76
77 return return_me;
78}
79
80void free_dictionary(char **dictionary) {
81 if (!dictionary) return;
82 int i = 0;
83
84 for (i = 0; strcmp(dictionary[i], ""); i++) {
85 free(dictionary[i]);
86 }
87
88 free(dictionary[i]);
89 free(dictionary);
90}
91
diff --git a/plist.h b/plist.h
new file mode 100644
index 0000000..1f18eb4
--- /dev/null
+++ b/plist.h
@@ -0,0 +1,17 @@
1/* plist.h
2 * contains structures and the like for plists
3 * written by fxchip
4 */
5
6#ifndef PLIST_H
7#define PLIST_H
8
9#include <libxml/parser.h>
10#include <libxml/tree.h>
11
12xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth);
13xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth);
14void free_plist(xmlDocPtr plist);
15xmlDocPtr new_plist();
16void free_dictionary(char **dictionary);
17#endif
diff --git a/usbmux.c b/usbmux.c
new file mode 100644
index 0000000..8c5fc34
--- /dev/null
+++ b/usbmux.c
@@ -0,0 +1,198 @@
1
2#include <sys/types.h>
3#include <arpa/inet.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "usbmux.h"
9
10extern int debug;
11
12usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) {
13 usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header));
14 conn->type = htonl(6);
15 conn->length = 28;
16 conn->sport = htons(s_port);
17 conn->dport = htons(d_port);
18 conn->scnt = 0;
19 conn->ocnt = 0;
20 conn->offset = 0x50;
21 conn->window = htons(0x0200);
22 conn->nullnull = 0x0000;
23 conn->length16 = 28;
24 return conn;
25}
26
27usbmux_version_header *version_header() {
28 usbmux_version_header *version = (usbmux_version_header*)malloc(sizeof(usbmux_version_header));
29 version->type = 0;
30 version->length = htonl(20);
31 version->major = htonl(1);
32 version->minor = 0;
33 version->allnull = 0;
34 return version;
35}
36
37/* mux_connect(phone, s_port, d_port)
38 * This is a higher-level USBMuxTCP-type function.
39 * phone: the iPhone to initialize a connection on.
40 * s_port: the source port
41 * d_port: the destination port -- 0xf27e for lockdownd.
42 * Initializes a connection on phone, with source port s_port and destination port d_port
43 *
44 * Returns a mux TCP header for the connection which is used for tracking and data transfer.
45 */
46
47usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) {
48 if (!phone || !s_port || !d_port) return NULL;
49 int bytes = 0;
50 // Initialize connection stuff
51 usbmux_tcp_header *new_connection;
52 new_connection = new_mux_packet(s_port, d_port);
53 usbmux_tcp_header *response;
54 response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header));
55 // blargg
56 if (new_connection) {
57 new_connection->tcp_flags = 0x02;
58 new_connection->length = htonl(new_connection->length);
59 new_connection->length16 = htons(new_connection->length16);
60
61 if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) {
62 bytes = recv_from_phone(phone, (char*)response, sizeof(*response));
63 if (response->tcp_flags != 0x12) return NULL;
64 else {
65 new_connection->tcp_flags = 0x10;
66 new_connection->scnt = 1;
67 new_connection->ocnt = 1;
68 return new_connection;
69 }
70 } else {
71 return NULL;
72 }
73 }
74
75 // if we get to this point it's probably bad
76 return NULL;
77}
78
79/* mux_close_connection(phone, connection)
80 * This is a higher-level USBmuxTCP-type function.
81 * phone: the iPhone to close a connection with.
82 * connection: the connection to close.
83 *
84 * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!!
85 */
86void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) {
87 if (!phone || !connection) return;
88
89 connection->tcp_flags = 0x04;
90 connection->scnt = htonl(connection->scnt);
91 connection->ocnt = htonl(connection->ocnt);
92 int bytes = 0;
93
94 bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800);
95 bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800);
96
97 free(connection);
98}
99
100/* mux_send(phone, connection, data, datalen)
101 * This is a higher-level USBMuxTCP-like function.
102 * phone: the iPhone to send to.
103 * connection: the connection we're sending data on.
104 * data: a pointer to the data to send.
105 * datalen: how much data we're sending.
106 *
107 * Returns number of bytes sent, minus the header (28), or -1 on error.
108 */
109int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) {
110 if (!phone || !connection || !data || datalen == 0) return -1;
111 // connection->scnt and connection->ocnt should already be in host notation...
112 // we don't need to change them juuuust yet.
113 int bytes = 0;
114 if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen);
115 char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding
116 // Set the length and pre-emptively htonl/htons it
117 connection->length = htonl(sizeof(*connection) + datalen);
118 connection->length16 = htons(sizeof(*connection) + datalen);
119
120 // Put scnt and ocnt into big-endian notation
121 connection->scnt = htonl(connection->scnt);
122 connection->ocnt = htonl(connection->ocnt);
123 // Concatenation of stuff in the buffer.
124 memcpy(buffer, connection, sizeof(*connection));
125 memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen);
126
127 // We have a buffer full of data, we should now send it to the phone.
128 if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer);
129
130
131 bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen);
132
133 // Now that we've sent it off, we can clean up after our sloppy selves.
134 free(buffer);
135
136 // Re-calculate scnt and ocnt
137 connection->scnt = ntohl(connection->scnt) + datalen;
138 connection->ocnt = ntohl(connection->ocnt);
139
140 // Revert lengths
141 connection->length = ntohl(connection->length);
142 connection->length16 = ntohs(connection->length16);
143
144 // Now return the bytes.
145 if (bytes < sizeof(*connection)+datalen) {
146 return -1; // blah
147 } else {
148 return bytes - 28; // actual length sent. :/
149 }
150
151 return bytes; // or something
152}
153
154/* mux_recv(phone, connection, data, datalen)
155 * This is a higher-level USBMuxTCP-like function
156 * phone: the phone to receive data from.
157 * connection: the connection to receive data on.
158 * data: where to put the data we receive.
159 * datalen: how much data to read.
160 *
161 * Returns: how many bytes were read, or -1 if something bad happens.
162 */
163
164int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) {
165 char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen);
166 int bytes = 0, my_datalen = 0;
167 if (debug) printf("mux_recv: datalen == %i\n", datalen);
168 bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen);
169 if (debug) printf("mux_recv: bytes == %i\n", bytes);
170 if (bytes < datalen) {
171 if (bytes < 28) {
172 // if they didn't do that annoying thing, something else mighta happened.
173 if (debug) printf("mux_recv: bytes too low anyway!\n");
174 free(buffer);
175 return -1;
176 } else if (bytes == 28) { // no data...
177 free(buffer);
178 return 0;
179 } else { // bytes > 28
180 my_datalen = ntohl(buffer[4]) - 28;
181 connection->ocnt += my_datalen;
182 memcpy(data, buffer+28, bytes - 28);
183 free(buffer);
184 if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28);
185 return bytes - 28;
186 }
187 } else {// all's good, they didn't do anything bonky.
188 my_datalen = ntohl(buffer[4]) - 28;
189 connection->ocnt += my_datalen;
190 memcpy(data, buffer+28, datalen);
191 free(buffer);
192 if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28);
193 return bytes - 28;
194 }
195
196 return bytes;
197}
198
diff --git a/usbmux.h b/usbmux.h
new file mode 100644
index 0000000..921f4b7
--- /dev/null
+++ b/usbmux.h
@@ -0,0 +1,39 @@
1
2#include <sys/types.h>
3#include <stdlib.h>
4#include <stdint.h>
5
6
7#ifndef USBMUX_H
8#define USBMUX_H
9
10#ifndef IPHONE_H
11#include "iphone.h"
12#endif
13
14typedef uint16_t uint16;
15typedef uint32_t uint32;
16typedef uint8_t uint8;
17
18
19typedef struct {
20 uint32 type, length;
21 uint16 sport, dport;
22 uint32 scnt, ocnt;
23 uint8 offset, tcp_flags;
24 uint16 window, nullnull, length16;
25} usbmux_tcp_header;
26
27usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port);
28
29typedef struct {
30 uint32 type, length, major, minor, allnull;
31} usbmux_version_header;
32
33usbmux_version_header *version_header();
34
35usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port);
36void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection);
37int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen);
38int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen);
39#endif