summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/Makefile.am7
-rw-r--r--tools/ideviceprovision.c421
2 files changed, 427 insertions, 1 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index c85bf13..6a4822b 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) 3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS)
4AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS) 4AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS)
5 5
6bin_PROGRAMS = idevice_id ideviceinfo idevicepair idevicesyslog ideviceimagemounter idevicescreenshot ideviceenterrecovery idevicedate idevicebackup idevicebackup2 6bin_PROGRAMS = idevice_id ideviceinfo idevicepair idevicesyslog ideviceimagemounter idevicescreenshot ideviceenterrecovery idevicedate idevicebackup idevicebackup2 ideviceprovision
7 7
8ideviceinfo_SOURCES = ideviceinfo.c 8ideviceinfo_SOURCES = ideviceinfo.c
9ideviceinfo_CFLAGS = $(AM_CFLAGS) 9ideviceinfo_CFLAGS = $(AM_CFLAGS)
@@ -54,3 +54,8 @@ idevicedate_SOURCES = idevicedate.c
54idevicedate_CFLAGS = $(AM_CFLAGS) 54idevicedate_CFLAGS = $(AM_CFLAGS)
55idevicedate_LDFLAGS = $(AM_LDFLAGS) 55idevicedate_LDFLAGS = $(AM_LDFLAGS)
56idevicedate_LDADD = ../src/libimobiledevice.la 56idevicedate_LDADD = ../src/libimobiledevice.la
57
58ideviceprovision_SOURCES = ideviceprovision.c
59ideviceprovision_CFLAGS = $(AM_CFLAGS)
60ideviceprovision_LDFLAGS = $(AM_LDFLAGS)
61ideviceprovision_LDADD = ../src/libimobiledevice.la
diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c
new file mode 100644
index 0000000..02b4d1e
--- /dev/null
+++ b/tools/ideviceprovision.c
@@ -0,0 +1,421 @@
1/*
2 * ideviceprovision.c
3 * Simple utility to install, get, or remove provisioning profiles
4 * to/from idevices
5 *
6 * Copyright (c) 2012 Nikias Bassen, All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <arpa/inet.h>
27
28#include <libimobiledevice/libimobiledevice.h>
29#include <libimobiledevice/lockdown.h>
30#include <libimobiledevice/misagent.h>
31
32static void print_usage(int argc, char **argv)
33{
34 char *name = NULL;
35
36 name = strrchr(argv[0], '/');
37 printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
38 printf("Display the current date or set it on a device.\n\n");
39 printf(" -d, --debug\t\tenable communication debugging\n");
40 printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n");
41 printf(" -i, --install FILE\tInstalls the provisioning profile specified by FILE.\n");
42 printf(" \tA valid .mobileprovision file is expected.\n");
43 printf(" -l, --list\t\tGet a list of all provisioning profiles on the device.\n");
44 printf(" -c, --copy PATH\tRetrieves all provisioning profiles from the device and\n");
45 printf(" \tstores them into the existing directory specified by PATH.\n");
46 printf(" \tThe files will be stored as UUID.mobileprovision\n");
47 printf(" -r, --remove UUID\tRemoves the provisioning profile identified by UUID.\n");
48 printf(" -h, --help\t\tprints usage information\n");
49 printf("\n");
50}
51
52enum {
53 OP_INSTALL,
54 OP_LIST,
55 OP_COPY,
56 OP_REMOVE,
57 NUM_OPS
58};
59
60#define ASN1_SEQUENCE 0x30
61#define ASN1_CONTAINER 0xA0
62#define ASN1_OBJECT_IDENTIFIER 0x06
63#define ASN1_OCTET_STRING 0x04
64
65static void asn1_next_item(unsigned char** p)
66{
67 if (*(*p+1) & 0x80) {
68 *p += 4;
69 } else {
70 *p += 3;
71 }
72}
73
74static int asn1_item_get_size(unsigned char* p)
75{
76 int res = 0;
77 if (*(p+1) & 0x80) {
78 uint16_t ws = 0;
79 memcpy(&ws, p+2, 2);
80 ws = ntohs(ws);
81 res = ws;
82 } else {
83 res = (int) *(p+1);
84 }
85 return res;
86}
87
88static void asn1_skip_item(unsigned char** p)
89{
90 int sz = asn1_item_get_size(*p);
91 *p += 2;
92 *p += sz;
93}
94
95static plist_t profile_get_embedded_plist(plist_t profile)
96{
97 if (plist_get_node_type(profile) != PLIST_DATA) {
98 fprintf(stderr, "%s: unexpected plist node type for profile (PLIST_DATA expected)\n", __func__);
99 return NULL;
100 }
101 char* bbuf = NULL;
102 uint64_t blen = 0;
103 plist_get_data_val(profile, &bbuf, &blen);
104 if (!bbuf) {
105 fprintf(stderr, "%s: could not get data value from plist node\n", __func__);
106 return NULL;
107 }
108
109 unsigned char* pp = (unsigned char*)bbuf;
110
111 if (*pp != ASN1_SEQUENCE) {
112 free(bbuf);
113 fprintf(stderr, "%s: unexpected profile data (0)\n", __func__);
114 return NULL;
115 }
116 uint16_t slen = asn1_item_get_size(pp);
117 if (slen+4 != (uint16_t)blen) {
118 free(bbuf);
119 fprintf(stderr, "%s: unexpected profile data (1)\n", __func__);
120 return NULL;
121 }
122 asn1_next_item(&pp);
123
124 if (*pp != ASN1_OBJECT_IDENTIFIER) {
125 free(bbuf);
126 fprintf(stderr, "%s: unexpected profile data (2)\n", __func__);
127 return NULL;
128 }
129 asn1_skip_item(&pp);
130
131 if (*pp != ASN1_CONTAINER) {
132 free(bbuf);
133 fprintf(stderr, "%s: unexpected profile data (3)\n", __func__);
134 return NULL;
135 }
136 asn1_next_item(&pp);
137
138 if (*pp != ASN1_SEQUENCE) {
139 free(bbuf);
140 fprintf(stderr, "%s: unexpected profile data (4)\n", __func__);
141 return NULL;
142 }
143 asn1_next_item(&pp);
144
145 int k = 0;
146 // go to the 3rd element (skip 2)
147 while (k < 2) {
148 asn1_skip_item(&pp);
149 k++;
150 }
151 if (*pp != ASN1_SEQUENCE) {
152 free(bbuf);
153 fprintf(stderr, "%s: unexpected profile data (5)\n", __func__);
154 return NULL;
155 }
156 asn1_next_item(&pp);
157
158 if (*pp != ASN1_OBJECT_IDENTIFIER) {
159 free(bbuf);
160 fprintf(stderr, "%s: unexpected profile data (6)\n", __func__);
161 return NULL;
162 }
163 asn1_skip_item(&pp);
164
165 if (*pp != ASN1_CONTAINER) {
166 free(bbuf);
167 fprintf(stderr, "%s: unexpected profile data (7)\n", __func__);
168 return NULL;
169 }
170 asn1_next_item(&pp);
171
172 if (*pp != ASN1_OCTET_STRING) {
173 free(bbuf);
174 fprintf(stderr, "%s: unexpected profile data (8)\n", __func__);
175 return NULL;
176 }
177 slen = asn1_item_get_size(pp);
178 asn1_next_item(&pp);
179
180 plist_t pl = NULL;
181 plist_from_xml((char*)pp, slen, &pl);
182 free(bbuf);
183
184 return pl;
185}
186
187int main(int argc, char *argv[])
188{
189 lockdownd_client_t client = NULL;
190 idevice_t device = NULL;
191 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
192 int i;
193 int op = -1;
194 const char* udid = NULL;
195 const char* param = NULL;
196
197 /* parse cmdline args */
198 for (i = 1; i < argc; i++) {
199 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
200 idevice_set_debug_level(1);
201 continue;
202 }
203 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
204 i++;
205 if (!argv[i] || (strlen(argv[i]) != 40)) {
206 print_usage(argc, argv);
207 return 0;
208 }
209 udid = argv[i];
210 continue;
211 }
212 else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--install")) {
213 i++;
214 if (!argv[i] || (strlen(argv[i]) < 1)) {
215 print_usage(argc, argv);
216 return 0;
217 }
218 param = argv[i];
219 op = OP_INSTALL;
220 continue;
221 }
222 else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--list")) {
223 op = OP_LIST;
224 }
225 else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--copy")) {
226 i++;
227 if (!argv[i] || (strlen(argv[i]) < 1)) {
228 print_usage(argc, argv);
229 return 0;
230 }
231 param = argv[i];
232 op = OP_COPY;
233 continue;
234 }
235 else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--remove")) {
236 i++;
237 if (!argv[i] || (strlen(argv[i]) < 1)) {
238 print_usage(argc, argv);
239 return 0;
240 }
241 param = argv[i];
242 op = OP_REMOVE;
243 continue;
244 }
245 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
246 print_usage(argc, argv);
247 return 0;
248 }
249 else {
250 print_usage(argc, argv);
251 return 0;
252 }
253 }
254
255 if ((op == -1) || (op >= NUM_OPS)) {
256 print_usage(argc, argv);
257 return 0;
258 }
259
260 ret = idevice_new(&device, udid);
261 if (ret != IDEVICE_E_SUCCESS) {
262 if (udid) {
263 printf("No device found with udid %s, is it plugged in?\n", udid);
264 } else {
265 printf("No device found, is it plugged in?\n");
266 }
267 return -1;
268 }
269
270 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "ideviceprovision")) {
271 idevice_free(device);
272 return -1;
273 }
274
275 uint16_t port = 0;
276 if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &port)) {
277 fprintf(stderr, "Could not start service \"com.apple.misagent\"\n");
278 lockdownd_client_free(client);
279 idevice_free(device);
280 return -1;
281 }
282 lockdownd_client_free(client);
283 client = NULL;
284
285 misagent_client_t mis = NULL;
286 if (misagent_client_new(device, port, &mis) != MISAGENT_E_SUCCESS) {
287 fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n");
288 lockdownd_client_free(client);
289 idevice_free(device);
290 return -1;
291 }
292
293 switch (op) {
294 case OP_INSTALL:
295 {
296 FILE* f = fopen(param, "rb");
297 if (!f) {
298 fprintf(stderr, "Could not open file '%s'\n", param);
299 break;
300 }
301 fseek(f, 0, SEEK_END);
302 long int size = ftell(f);
303 fseek(f, 0, SEEK_SET);
304
305 if (size >= 0x1000000) {
306 fprintf(stderr, "The file '%s' is too large for processing.\n", param);
307 fclose(f);
308 break;
309 }
310
311 char* buf = malloc(size);
312 if (!buf) {
313 fprintf(stderr, "Could not allocate memory...\n");
314 fclose(f);
315 break;
316 }
317
318 long int cur = 0;
319 while (cur < size) {
320 ssize_t r = fread(buf+cur, 1, 512, f);
321 if (r <= 0) {
322 break;
323 }
324 cur += r;
325 }
326 fclose(f);
327
328 if (cur != size) {
329 free(buf);
330 fprintf(stderr, "Could not read in file '%s' (size %ld read %ld)\n", param, size, cur);
331 break;
332 }
333
334 uint64_t psize = size;
335 plist_t pdata = plist_new_data(buf, psize);
336
337 if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) {
338 printf("Profile '%s' installed successfully.\n", param);
339 } else {
340 int sc = misagent_get_status_code(mis);
341 fprintf(stderr, "Could not install profile '%s', status code: 0x%x\n", param, sc);
342 }
343 free(buf);
344 }
345 break;
346 case OP_LIST:
347 case OP_COPY:
348 {
349 plist_t profiles = NULL;
350 if (misagent_copy(mis, &profiles) == MISAGENT_E_SUCCESS) {
351 uint32_t num_profiles = plist_array_get_size(profiles);
352 printf("Device has %d provisioning %s installed:\n", num_profiles, (num_profiles == 1) ? "profile" : "profiles");
353 uint32_t j;
354 for (j = 0; j < num_profiles; j++) {
355 char* p_name = NULL;
356 char* p_uuid = NULL;
357 plist_t profile = plist_array_get_item(profiles, j);
358 plist_t pl = profile_get_embedded_plist(profile);
359 if (pl && (plist_get_node_type(pl) == PLIST_DICT)) {
360 plist_t node;
361 node = plist_dict_get_item(pl, "Name");
362 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
363 plist_get_string_val(node, &p_name);
364 }
365 node = plist_dict_get_item(pl, "UUID");
366 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
367 plist_get_string_val(node, &p_uuid);
368 }
369 }
370 printf("%s - %s\n", (p_uuid) ? p_uuid : "(unknown id)", (p_name) ? p_name : "(no name)");
371 if (op == OP_COPY) {
372 char pfname[512];
373 if (p_uuid) {
374 sprintf(pfname, "%s/%s.mobileprovision", param, p_uuid);
375 } else {
376 sprintf(pfname, "%s/profile%d.mobileprovision", param, j);
377 }
378 FILE* f = fopen(pfname, "wb");
379 if (f) {
380 char* dt = NULL;
381 uint64_t ds = 0;
382 plist_get_data_val(profile, &dt, &ds);
383 fwrite(dt, 1, ds, f);
384 fclose(f);
385 printf(" => %s\n", pfname);
386 } else {
387 fprintf(stderr, "Could not open '%s' for writing\n", pfname);
388 }
389 }
390 if (p_uuid) {
391 free(p_uuid);
392 }
393 if (p_name) {
394 free(p_name);
395 }
396 }
397 } else {
398 int sc = misagent_get_status_code(mis);
399 fprintf(stderr, "Could not get installed profiles from device, status code: 0x%x\n", sc);
400 }
401 }
402 break;
403 case OP_REMOVE:
404 if (misagent_remove(mis, param) == MISAGENT_E_SUCCESS) {
405 printf("Profile '%s' removed.\n", param);
406 } else {
407 int sc = misagent_get_status_code(mis);
408 fprintf(stderr, "Could not remove profile '%s', status code 0x%x\n", param, sc);
409 }
410 break;
411 default:
412 break;
413 }
414
415 misagent_client_free(mis);
416
417 idevice_free(device);
418
419 return 0;
420}
421