summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Matt Colyer2008-07-29 10:13:37 -0700
committerGravatar Matt Colyer2008-07-29 10:13:37 -0700
commit3dc130f3049e250b2d5c0b48af1995fda2fad3d4 (patch)
tree9d801459ef68e83a0d4ca038c0589d8e4c8aa2b2 /src
parent6039e5bbfc36aa5210295c38f251ed178ce5adbb (diff)
downloadlibimobiledevice-3dc130f3049e250b2d5c0b48af1995fda2fad3d4.tar.gz
libimobiledevice-3dc130f3049e250b2d5c0b48af1995fda2fad3d4.tar.bz2
Autotooled the project with very basic versioning support.
Diffstat (limited to 'src')
-rw-r--r--src/AFC.c381
-rw-r--r--src/AFC.h80
-rw-r--r--src/Makefile.am5
-rw-r--r--src/iphone.c156
-rw-r--r--src/iphone.h29
-rw-r--r--src/lockdown.c372
-rw-r--r--src/lockdown.h36
-rw-r--r--src/main.c104
-rw-r--r--src/main.h1
-rw-r--r--src/plist.c91
-rw-r--r--src/plist.h17
-rw-r--r--src/usbmux.c198
-rw-r--r--src/usbmux.h39
13 files changed, 1509 insertions, 0 deletions
diff --git a/src/AFC.c b/src/AFC.c
new file mode 100644
index 0000000..f3d538e
--- /dev/null
+++ b/src/AFC.c
@@ -0,0 +1,381 @@
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 = client->afc_packet->entire_length = client->afc_packet->this_length = 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, offset = 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 if (!client->afc_packet->entire_length) client->afc_packet->entire_length = client->afc_packet->this_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket);
59 if (!client->afc_packet->this_length) client->afc_packet->this_length = sizeof(AFCPacket);
60
61 if (client->afc_packet->this_length != client->afc_packet->entire_length) {
62 // We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters
63 // And everything beyond that is the next packet. (for writing)
64 char *buffer = (char*)malloc(client->afc_packet->this_length);
65 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket));
66 offset = client->afc_packet->this_length - sizeof(AFCPacket);
67 if (debug) printf("dispatch_AFC_packet: Offset: %i\n", offset);
68 if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) {
69 if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length);
70 free(buffer);
71 return 0;
72 }
73 if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n");
74 memcpy(buffer+sizeof(AFCPacket), data, offset);
75 bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length);
76 free(buffer);
77 if (bytes <= 0) { return 0; }
78 if (debug) {
79 printf("dispatch_AFC_packet: sent the first now go with the second\n");
80 printf("Length: %i\n", length-offset);
81 printf("Buffer: \n");
82 fwrite(data+offset, 1, length-offset, stdout);
83 }
84
85
86 bytes = mux_send(client->phone, client->connection, data+offset, length-offset);
87 if (bytes <= 0) { return 0; }
88 else { return bytes; }
89 } else {
90 if (debug) printf("dispatch_AFC_packet doin things the old way\n");
91 char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length);
92 if (debug) printf("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length);
93 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket));
94 if (debug) printf("dispatch_AFC_packet packet data follows\n");
95 if (length > 0) { memcpy(buffer+sizeof(AFCPacket), data, length); buffer[sizeof(AFCPacket)+length] = '\0'; }
96 if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout);
97 if (debug) printf("\n");
98 bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length);
99 if (bytes <= 0) return 0;
100 else return bytes;
101 }
102 return 0;
103}
104
105int receive_AFC_data(AFClient *client, char **dump_here) {
106 AFCPacket *r_packet;
107 char *buffer = (char*)malloc(sizeof(AFCPacket) * 4);
108 int bytes = 0, recv_len = 0;
109
110 bytes = mux_recv(client->phone, client->connection, buffer, sizeof(AFCPacket) * 4);
111 if (bytes <= 0) {
112 free(buffer);
113 printf("Just didn't get enough.\n");
114 *dump_here = NULL;
115 return 0;
116 }
117
118 r_packet = (AFCPacket*)malloc(sizeof(AFCPacket));
119 memcpy(r_packet, buffer, sizeof(AFCPacket));
120
121 if (r_packet->entire_length == r_packet->this_length && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) {
122 *dump_here = (char*)malloc(sizeof(char) * (r_packet->entire_length-sizeof(AFCPacket)));
123 memcpy(*dump_here, buffer+sizeof(AFCPacket), r_packet->entire_length-sizeof(AFCPacket));
124 free(buffer);
125 free(r_packet);
126 return r_packet->entire_length - sizeof(AFCPacket);
127 }
128
129 uint32 param1 = buffer[sizeof(AFCPacket)];
130 free(buffer);
131
132 if (r_packet->operation == 0x01 && !((client->afc_packet->operation == AFC_DELETE && param1 == 7))) {
133 if (debug) printf("Oops? Bad operation code received.\n");
134 if (param1 == 0) {
135 if (debug) printf("... false alarm, but still\n");
136 return 1;
137 }
138 else { if (debug) printf("Errno %i\n", param1); }
139 free(r_packet);
140 *dump_here = NULL;
141 return 0;
142 } else {
143 if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length);
144 }
145
146 recv_len = r_packet->entire_length - r_packet->this_length;
147 free(r_packet);
148 if (!recv_len) return bytes;
149 buffer = (char*)malloc(sizeof(char) * recv_len);
150 bytes = mux_recv(client->phone, client->connection, buffer, recv_len);
151 if (bytes <= 0) {
152 free(buffer);
153 printf("Didn't get it at the second pass.\n");
154 *dump_here = NULL;
155 return 0;
156 }
157
158 *dump_here = buffer; // what they do beyond this point = not my problem
159 return bytes;
160}
161
162char **afc_get_dir_list(AFClient *client, char *dir) {
163 client->afc_packet->operation = AFC_LIST_DIR;
164 int bytes = 0;
165 char *blah = NULL, **list = NULL;
166 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
167 bytes = dispatch_AFC_packet(client, dir, strlen(dir));
168 if (!bytes) return NULL;
169
170 bytes = receive_AFC_data(client, &blah);
171 if (!bytes && !blah) return NULL;
172
173 list = make_strings_list(blah, bytes);
174 free(blah);
175 return list;
176}
177
178char **make_strings_list(char *tokens, int true_length) {
179 if (!tokens || !true_length) return NULL;
180 int nulls = 0, i = 0, j = 0;
181 char **list = NULL;
182
183 nulls = count_nullspaces(tokens, true_length);
184 list = (char**)malloc(sizeof(char*) * (nulls + 1));
185 for (i = 0; i < nulls; i++) {
186 list[i] = strdup(tokens+j);
187 j += strlen(list[i]) + 1;
188 }
189 list[i] = strdup("");
190 return list;
191}
192
193int afc_delete_file(AFClient *client, const char *path) {
194 if (!client || !path || !client->afc_packet || !client->phone ||!client->connection) return 0;
195
196 char *receive = NULL;
197 client->afc_packet->this_length = client->afc_packet->entire_length = 0;
198 client->afc_packet->operation = AFC_DELETE;
199 int bytes;
200 bytes = dispatch_AFC_packet(client, path, strlen(path));
201 if (bytes <= 0) return 0;
202
203 bytes = receive_AFC_data(client, &receive);
204 free(receive);
205 if (bytes <= 0) return 0;
206 else return 1;
207}
208
209int afc_rename_file(AFClient *client, const char *from, const char *to) {
210 if (!client || !from || !to || !client->afc_packet || !client->phone || !client->connection) return 0;
211
212 char *receive = NULL;
213 char *send = (char*)malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32)));
214 int bytes = 0;
215
216 memcpy(send, from, strlen(from)+1);
217 memcpy(send+strlen(from)+1, to, strlen(to));
218 fwrite(send, 1, strlen(from)+1+strlen(to), stdout);
219 printf("\n");
220 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
221 client->afc_packet->operation = AFC_RENAME;
222 bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2);
223 if (bytes <= 0) return 0;
224
225 bytes = receive_AFC_data(client, &receive);
226 free(receive);
227 if (bytes <= 0) return 0;
228 else return 1;
229}
230
231
232
233AFCFile *afc_get_file_info(AFClient *client, char *path) {
234 client->afc_packet->operation = AFC_GET_INFO;
235 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
236 dispatch_AFC_packet(client, path, strlen(path));
237
238 char *received, **list;
239 AFCFile *my_file;
240 int length, i = 0;
241
242 length = receive_AFC_data(client, &received);
243 list = make_strings_list(received, length);
244 free(received);
245 if (list) {
246 my_file = (AFCFile *)malloc(sizeof(AFCFile));
247 for (i = 0; strcmp(list[i], ""); i++) {
248 if (!strcmp(list[i], "st_size")) {
249 my_file->size = atoi(list[i+1]);
250 }
251
252
253 if (!strcmp(list[i], "st_blocks")) {
254 my_file->blocks = atoi(list[i+1]);
255 }
256
257 if (!strcmp(list[i], "st_ifmt")) {
258 if (!strcmp(list[i+1], "S_IFREG")) {
259 my_file->type = S_IFREG;
260 } else if (!strcmp(list[i+1], "S_IFDIR")) {
261 my_file->type = S_IFDIR;
262 }
263 }
264 }
265 free_dictionary(list);
266 return my_file;
267 } else {
268 return NULL;
269 }
270}
271
272AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) {
273 if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL;
274 if (!client ||!client->connection || !client->phone ||!client->afc_packet) return NULL;
275 char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1));
276 AFCFile *file_infos = NULL;
277 memcpy(further_data, &file_mode, 4);
278 uint32 ag = 0;
279 memcpy(further_data+4, &ag, 4);
280 memcpy(further_data+8, filename, strlen(filename));
281 further_data[8+strlen(filename)] = '\0';
282 int bytes = 0, length_thing = 0;
283 client->afc_packet->operation = AFC_FILE_OPEN;
284
285 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
286 bytes = dispatch_AFC_packet(client, further_data, 8+strlen(filename));
287 free(further_data);
288 if (bytes <= 0) {
289 if (debug) printf("didn't read enough\n");
290 return NULL;
291 } else {
292 length_thing = receive_AFC_data(client, &further_data);
293 if (length_thing && further_data) {
294 file_infos = afc_get_file_info(client, filename);
295 memcpy(&file_infos->filehandle, further_data, 4);
296 return file_infos;
297 } else {
298 if (debug) printf("didn't get further data or something\n");
299 return NULL;
300 }
301 }
302 if (debug) printf("what the fuck\n");
303 return NULL;
304}
305
306int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) {
307 if (!client || !client->afc_packet || !client->phone || !client->connection || !file) return -1;
308 AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket));
309 char *input = NULL;
310 packet->unknown1 = packet->unknown2 = 0;
311 packet->filehandle = file->filehandle;
312 packet->size = length;
313 int bytes = 0;
314
315 client->afc_packet->operation = AFC_READ;
316 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
317 bytes = dispatch_AFC_packet(client, (char*)packet, sizeof(AFCFilePacket));
318
319 if (bytes > 0) {
320 bytes = receive_AFC_data(client, &input);
321 if (bytes <= 0) {
322 if (input) free(input);
323 return -1;
324 } else {
325 memcpy(data, input, (bytes > length) ? length : bytes);
326 free(input);
327 return (bytes > length) ? length : bytes;
328 }
329 } else {
330 return -1;
331 }
332 return 0;
333}
334
335int afc_write_file(AFClient *client, AFCFile *file, char *data, int length) {
336 char *acknowledgement = NULL;
337 if (!client ||!client->afc_packet ||!client->phone || !client->connection || !file) return -1;
338 client->afc_packet->this_length = sizeof(AFCPacket) + 8;
339 client->afc_packet->entire_length = client->afc_packet->this_length + length;
340 client->afc_packet->operation = AFC_WRITE;
341 if (debug) printf("afc_write_file: Write length: %i\n", length);
342 uint32 zero = 0, bytes = 0;
343
344 char *out_buffer = NULL;
345 out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
346 memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32));
347 memcpy(out_buffer+4, (char*)&zero, sizeof(uint32));
348 memcpy(out_buffer+8, data, length);
349
350 bytes = dispatch_AFC_packet(client, out_buffer, length + 8);
351 if (!bytes) return -1;
352
353 zero = bytes;
354 bytes = receive_AFC_data(client, &acknowledgement);
355 if (bytes <= 0) {
356 if (debug) printf("afc_write_file: uh oh?\n");
357 }
358
359 return zero;
360}
361
362void afc_close_file(AFClient *client, AFCFile *file) {
363 char *buffer = malloc(sizeof(char) * 8);
364 uint32 zero = 0;
365 if (debug) printf("File handle %i\n", file->filehandle);
366 memcpy(buffer, &file->filehandle, sizeof(uint32));
367 memcpy(buffer+sizeof(uint32), &zero, sizeof(zero));
368 client->afc_packet->operation = AFC_FILE_CLOSE;
369 int bytes = 0;
370 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
371 bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8);
372
373 free(buffer);
374 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
375 if (!bytes) return;
376
377 bytes = receive_AFC_data(client, &buffer);
378 return;
379 if (buffer) free(buffer); // we're *SUPPOSED* to get an "error" here.
380}
381
diff --git a/src/AFC.h b/src/AFC.h
new file mode 100644
index 0000000..787b9fe
--- /dev/null
+++ b/src/AFC.h
@@ -0,0 +1,80 @@
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_DELETE = 0x00000008,
57 AFC_RENAME = 0x00000018,
58 AFC_SUCCESS_RESPONSE = 0x00000002,
59 AFC_FILE_OPEN = 0x0000000d,
60 AFC_FILE_CLOSE = 0x00000014,
61 AFC_FILE_HANDLE = 0x0000000e,
62 AFC_READ = 0x0000000f,
63 AFC_WRITE = 0x00000010
64};
65
66AFClient *afc_connect(iPhone *phone, int s_port, int d_port);
67void afc_disconnect(AFClient *client);
68int count_nullspaces(char *string, int number);
69char **make_strings_list(char *tokens, int true_length);
70int dispatch_AFC_packet(AFClient *client, char *data, int length);
71int receive_AFC_data(AFClient *client, char **dump_here);
72
73char **afc_get_dir_list(AFClient *client, char *dir);
74AFCFile *afc_get_file_info(AFClient *client, char *path);
75AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode);
76void afc_close_file(AFClient *client, AFCFile *file);
77int afc_read_file(AFClient *client, AFCFile *file, char *data, int length);
78int afc_write_file(AFClient *client, AFCFile *file, char *data, int length);
79int afc_delete_file(AFClient *client, const char *path);
80int afc_rename_file(AFClient *client, const char *from, const char *to);
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..cb05d95
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,5 @@
1AM_CFLAGS = `xml2-config --cflags`
2AM_LDFLAGS = `xml2-config --libs` -lusb -lgnutls
3
4bin_PROGRAMS = iphoneclient
5iphoneclient_SOURCES = usbmux.c main.c iphone.c plist.c lockdown.c AFC.c
diff --git a/src/iphone.c b/src/iphone.c
new file mode 100644
index 0000000..4ddb571
--- /dev/null
+++ b/src/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/src/iphone.h b/src/iphone.h
new file mode 100644
index 0000000..a49b7ef
--- /dev/null
+++ b/src/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/src/lockdown.c b/src/lockdown.c
new file mode 100644
index 0000000..34a98f7
--- /dev/null
+++ b/src/lockdown.c
@@ -0,0 +1,372 @@
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_anon_client_credentials_t anoncred;
153 gnutls_certificate_credentials_t xcred;
154 if (debug) printf("We started the session OK, now trying GnuTLS\n");
155 errno = 0;
156 gnutls_global_init();
157 //gnutls_anon_allocate_client_credentials(&anoncred);
158 gnutls_certificate_allocate_credentials(&xcred);
159 gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM);
160 gnutls_init(control->ssl_session, GNUTLS_CLIENT);
161 {
162 int protocol_priority[16] = {GNUTLS_SSL3, 0 };
163 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
164 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
165 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
166 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
167
168 gnutls_cipher_set_priority(*control->ssl_session, cipher_priority);
169 gnutls_compression_set_priority(*control->ssl_session, comp_priority);
170 gnutls_kx_set_priority(*control->ssl_session, kx_priority);
171 gnutls_protocol_set_priority( *control->ssl_session, protocol_priority);
172 gnutls_mac_set_priority(*control->ssl_session, mac_priority);
173
174 }
175 gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me.
176
177 if (debug) printf("GnuTLS step 1...\n");
178 gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control);
179 if (debug) printf("GnuTLS step 2...\n");
180 gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func)&lockdownd_secuwrite);
181 if (debug) printf("GnuTLS step 3...\n");
182 gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func)&lockdownd_securead);
183 if (debug) printf("GnuTLS step 4 -- now handshaking...\n");
184
185 if (errno && debug) printf("WARN: errno says %s before handshake!\n", strerror(errno));
186 return_me = gnutls_handshake(*control->ssl_session);
187 if (debug) printf("GnuTLS handshake done...\n");
188
189 free_dictionary(dictionary);
190
191 if (return_me != GNUTLS_E_SUCCESS) {
192 if (debug) printf("GnuTLS reported something wrong.\n");
193 gnutls_perror(return_me);
194 if (debug) printf("oh.. errno says %s\n", strerror(errno));
195 return 0;
196 } else {
197 control->in_SSL = 1;
198 return 1;
199 }
200 }
201 }
202
203 if (debug) {
204 printf("Apparently failed negotiating with lockdownd.\n");
205 printf("Responding dictionary: \n");
206 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
207 printf("\t%s: %s\n", dictionary[i], dictionary[i+1]);
208 }
209 }
210
211 free_dictionary(dictionary);
212 return 0;
213 } else {
214 if (debug) printf("Didn't get enough bytes.\n");
215 return 0;
216 }
217}
218
219ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) {
220 int bytes = 0;
221 lockdownd_client *control;
222 control = (lockdownd_client*)transport;
223 if (debug) printf("lockdownd_secuwrite() called\n");
224 if (debug) printf("pre-send\nlength = %i\n", length);
225 bytes = mux_send(control->iphone, control->connection, buffer, length);
226 if (debug) printf("post-send\nsent %i bytes\n", bytes);
227 if (debug) {
228 FILE *my_ssl_packet = fopen("sslpacketwrite.out", "w+");
229 fwrite(buffer, 1, length, my_ssl_packet);
230 fflush(my_ssl_packet);
231 printf("Wrote SSL packet to drive, too.\n");
232 fclose(my_ssl_packet);
233 }
234
235 return bytes;
236}
237
238ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) {
239 int bytes = 0, pos_start_fill = 0;
240 char *hackhackhack = NULL;
241 lockdownd_client *control;
242 control = (lockdownd_client*)transport;
243 if (debug) printf("lockdownd_securead() called\nlength = %i\n", length);
244 // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more.
245 if (control->gtls_buffer_hack_len > 0) {
246 if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got
247 length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length
248 pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at
249 memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially
250 free(control->gtls_buffer_hack); // free our memory, it's not chained anymore
251 control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore
252 if (debug) printf("Did a partial fill to help quench thirst for data\n");
253 } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less...
254 control->gtls_buffer_hack_len -= length; // subtract what they're asking for
255 memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer
256 hackhackhack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer.
257 memcpy(hackhackhack, control->gtls_buffer_hack+length, control->gtls_buffer_hack_len); // Move what's left into the new one
258 free(control->gtls_buffer_hack); // Free the old one
259 control->gtls_buffer_hack = hackhackhack; // And make it the new one.
260 hackhackhack = NULL;
261 if (debug) printf("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len);
262 return length; // hand it over.
263 } else { // length == hack length
264 memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs
265 free(control->gtls_buffer_hack); // free our "obligation"
266 control->gtls_buffer_hack_len = 0; // free our "obligation"
267 if (debug) printf("Satiated the thirst for data; now we have to eventually receive again.\n");
268 return length; // hand it over
269 }
270 }
271 // End buffering hack!
272 char *recv_buffer = (char*)malloc(sizeof(char) * (length * 1000)); // ensuring nothing stupid happens
273
274 if (debug) printf("pre-read\nclient wants %i bytes\n", length);
275 bytes = mux_recv(control->iphone, control->connection, recv_buffer, (length * 1000));
276 if (debug) printf("post-read\nwe got %i bytes\n", bytes);
277 if (debug && bytes < 0) {
278 printf("lockdownd_securead(): uh oh\n");
279 printf("I believe what we have here is a failure to communicate... libusb says %s but strerror says %s\n", usb_strerror(), strerror(errno));
280 return bytes + 28; // an errno
281 }
282 if (bytes >= length) {
283 if (bytes > length) {
284 if (debug) printf("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n");
285 if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet
286 //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution!
287 control->gtls_buffer_hack_len += bytes-length;
288 control->gtls_buffer_hack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len);
289 memcpy(control->gtls_buffer_hack, recv_buffer+length, control->gtls_buffer_hack_len);
290 } else { // if there is.
291 control->gtls_buffer_hack = realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length));
292 memcpy(control->gtls_buffer_hack+control->gtls_buffer_hack_len, recv_buffer+length, bytes-length);
293 control->gtls_buffer_hack_len += bytes - length;
294 }
295 }
296 memcpy(buffer+pos_start_fill, recv_buffer, length);
297 free(recv_buffer);
298 if (bytes == length) { if (debug) printf("Returning how much we received.\n"); return bytes; }
299 else { if (debug) printf("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len); return length; }
300 }
301 return bytes;
302}
303
304int lockdownd_start_service(lockdownd_client *control, const char *service) {
305 if (!control) return 0;
306 if (!control->in_SSL && !lockdownd_start_SSL_session(control, "29942970-207913891623273984")) return 0;
307
308 char *XML_query, **dictionary;
309 uint32 length, i = 0, port = 0;
310 uint8 result = 0;
311
312 xmlDocPtr plist = new_plist();
313 xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
314 xmlNode *key;
315 key = add_key_str_dict_element(plist, dict, "Request", "StartService", 1);
316 if (!key) { xmlFreeDoc(plist); return 0; }
317 key = add_key_str_dict_element(plist, dict, "Service", service, 1);
318 if (!key) { xmlFreeDoc(plist); return 0; }
319
320 xmlDocDumpMemory(plist, &XML_query, &length);
321
322 lockdownd_send(control, XML_query, length);
323 free(XML_query);
324
325 length = lockdownd_recv(control, &XML_query);
326
327 xmlFreeDoc(plist);
328
329 if (length <= 0) return 0;
330 else {
331 plist = xmlReadMemory(XML_query, length, NULL, NULL, 0);
332 if (!plist) return 0;
333 dict = xmlDocGetRootElement(plist);
334 if (!dict) return 0;
335 for (dict = dict->children; dict; dict = dict->next) {
336 if (!xmlStrcmp(dict->name, "dict")) break;
337 }
338
339 if (!dict) return 0;
340 dictionary = read_dict_element_strings(dict);
341
342 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
343 if (debug) printf("lockdownd_start_service() dictionary %s: %s\n", dictionary[i], dictionary[i+1]);
344
345 if (!xmlStrcmp(dictionary[i], "Port")) {
346 port = atoi(dictionary[i+1]);
347 if (debug) printf("lockdownd_start_service() atoi'd port: %i\n", port);
348 }
349
350 if (!xmlStrcmp(dictionary[i], "Result")) {
351 if (!xmlStrcmp(dictionary[i+1], "Success")) {
352 result = 1;
353 }
354 }
355 }
356
357 if (debug) {
358 printf("lockdownd_start_service(): DATA RECEIVED:\n\n");
359 fwrite(XML_query, 1, length, stdout);
360 printf("end data received by lockdownd_start_service()\n");
361 }
362
363 free(XML_query);
364 xmlFreeDoc(plist);
365 free_dictionary(dictionary);
366 if (port && result) return port;
367 else return 0;
368 }
369
370 return 0;
371}
372
diff --git a/src/lockdown.h b/src/lockdown.h
new file mode 100644
index 0000000..0acd624
--- /dev/null
+++ b/src/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/src/main.c b/src/main.c
new file mode 100644
index 0000000..e4007e9
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,104 @@
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 port = lockdownd_start_service(control, "com.apple.afc");
44 }
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 my_file = afc_open_file(afc, "/readme.libiphone.fx", AFC_FILE_WRITE);
74 if (my_file) {
75 char *outdatafile = strdup("this is a bitchin text file\n");
76 bytes = afc_write_file(afc, my_file, outdatafile, strlen(outdatafile));
77 free(outdatafile);
78 if (bytes > 0) printf("Wrote a surprise. ;)\n");
79 else printf("I wanted to write a surprise, but... :(\n");
80 afc_close_file(afc, my_file);
81 free(my_file);
82 }
83 printf("Deleting a file...\n");
84 bytes = afc_delete_file(afc, "/delme");
85 if (bytes) printf("Success.\n");
86 else printf("Failure.\n");
87
88 printf("Renaming a file...\n");
89 bytes = afc_rename_file(afc, "/renme", "/renme2");
90 if (bytes > 0) printf("Success.\n");
91 else printf("Failure.\n");
92 }
93 afc_disconnect(afc);
94 } else {
95 printf("Start service failure.\n");
96 }
97
98 printf("All done.\n");
99
100 free_iPhone(phone);
101
102 return 0;
103}
104
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1 @@
diff --git a/src/plist.c b/src/plist.c
new file mode 100644
index 0000000..cbd6302
--- /dev/null
+++ b/src/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/src/plist.h b/src/plist.h
new file mode 100644
index 0000000..1f18eb4
--- /dev/null
+++ b/src/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/src/usbmux.c b/src/usbmux.c
new file mode 100644
index 0000000..8c5fc34
--- /dev/null
+++ b/src/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/src/usbmux.h b/src/usbmux.h
new file mode 100644
index 0000000..921f4b7
--- /dev/null
+++ b/src/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