summaryrefslogtreecommitdiffstats
path: root/src/preflight.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/preflight.c')
-rw-r--r--src/preflight.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/preflight.c b/src/preflight.c
new file mode 100644
index 0000000..0041b21
--- /dev/null
+++ b/src/preflight.c
@@ -0,0 +1,271 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <pthread.h>
30
31#include <sys/time.h>
32
33#include <libimobiledevice/libimobiledevice.h>
34#include <libimobiledevice/lockdown.h>
35#include <libimobiledevice/notification_proxy.h>
36
37#include "preflight.h"
38#include "client.h"
39#include "log.h"
40
41#ifdef HAVE_LIBIMOBILEDEVICE
42enum connection_type {
43 CONNECTION_USBMUXD = 1
44};
45
46struct idevice_private {
47 char *udid;
48 enum connection_type conn_type;
49 void *conn_data;
50};
51
52extern void userpref_get_system_buid(char **systembuid);
53
54struct np_cb_data {
55 idevice_t dev;
56 np_client_t np;
57};
58
59static void set_untrusted_host_buid(lockdownd_client_t lockdown)
60{
61 char* system_buid = NULL;
62 userpref_get_system_buid(&system_buid);
63 usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid);
64 lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid));
65 free(system_buid);
66}
67
68static void np_callback(const char* notification, void* userdata)
69{
70 struct np_cb_data *cbdata = (struct np_cb_data*)userdata;
71 idevice_t dev = cbdata->dev;
72 struct idevice_private *_dev = (struct idevice_private*)dev;
73
74 lockdownd_client_t lockdown = NULL;
75 lockdownd_error_t lerr;
76
77 if (strlen(notification) == 0) {
78 cbdata->np = NULL;
79 return;
80 }
81
82 if (strcmp(notification, "com.apple.mobile.lockdown.request_pair") == 0) {
83 usbmuxd_log(LL_INFO, "%s: user trusted this computer on device %s, pairing now", __func__, _dev->udid);
84 lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd");
85 if (lerr != LOCKDOWN_E_SUCCESS) {
86 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr);
87 return;
88 }
89
90 lerr = lockdownd_pair(lockdown, NULL);
91 if (lerr != LOCKDOWN_E_SUCCESS) {
92 usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
93 lockdownd_client_free(lockdown);
94 return;
95 }
96 lockdownd_client_free(lockdown);
97 // device will reconnect by itself at this point.
98
99 } else if (strcmp(notification, "com.apple.mobile.lockdown.request_host_buid") == 0) {
100 lerr = lockdownd_client_new(cbdata->dev, &lockdown, "usbmuxd");
101 if (lerr != LOCKDOWN_E_SUCCESS) {
102 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr);
103 } else {
104 set_untrusted_host_buid(lockdown);
105 lockdownd_client_free(lockdown);
106 }
107 }
108}
109
110static void* preflight_worker_handle_device_add(void* userdata)
111{
112 struct device_info *info = (struct device_info*)userdata;
113 struct idevice_private *_dev = (struct idevice_private*)malloc(sizeof(struct idevice_private));
114 _dev->udid = strdup(info->serial);
115 _dev->conn_type = CONNECTION_USBMUXD;
116 _dev->conn_data = (void*)(long)info->id;
117
118 idevice_t dev = (idevice_t)_dev;
119
120 lockdownd_client_t lockdown;
121 lockdownd_error_t lerr;
122
123 lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd");
124 if (lerr != LOCKDOWN_E_SUCCESS) {
125 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr);
126 goto leave;
127 }
128
129 char *type = NULL;
130 lerr = lockdownd_query_type(lockdown, &type);
131 if (!type) {
132 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get lockdownd type from device %s, lockdown error %d", __func__, _dev->udid, lerr);
133 goto leave;
134 }
135
136 if (strcmp(type, "com.apple.mobile.lockdown") != 0) {
137 // make restore mode devices visible
138 client_device_add(info);
139 goto leave;
140 }
141
142 char *host_id = NULL;
143 userpref_device_record_get_host_id(dev->udid, &host_id);
144 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
145 free(host_id);
146 if (lerr == LOCKDOWN_E_SUCCESS) {
147 usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid);
148 client_device_add(info);
149 goto leave;
150 }
151
152 usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr);
153 if (lerr == LOCKDOWN_E_INVALID_HOST_ID) {
154 usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid);
155 }
156
157 plist_t value = NULL;
158 lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value);
159 if (lerr != LOCKDOWN_E_SUCCESS) {
160 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
161 goto leave;
162 }
163
164 char* version_str = NULL;
165 plist_get_string_val(value, &version_str);
166 if (!version_str) {
167 usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
168 goto leave;
169 }
170
171 int version_major = strtol(version_str, NULL, 10);
172 if (version_major >= 7) {
173 // ============== iOS 7.0 and beyond =============
174 usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid);
175
176 set_untrusted_host_buid(lockdown);
177
178 lockdownd_service_descriptor_t service = NULL;
179 lerr = lockdownd_start_service(lockdown, "com.apple.mobile.insecure_notification_proxy", &service);
180 if (lerr != LOCKDOWN_E_SUCCESS) {
181 usbmuxd_log(LL_ERROR, "%s: ERROR: Could not start insecure_notification_proxy on %s, lockdown error %d", __func__, _dev->udid, lerr);
182 goto leave;
183 }
184
185 np_client_t np = NULL;
186 np_client_new(dev, service, &np);
187
188 lockdownd_service_descriptor_free(service);
189 service = NULL;
190
191 lockdownd_client_free(lockdown);
192 lockdown = NULL;
193
194 struct np_cb_data cbdata;
195 cbdata.dev = dev;
196 cbdata.np = np;
197
198 np_set_notify_callback(np, np_callback, (void*)&cbdata);
199
200 const char* spec[] = {
201 "com.apple.mobile.lockdown.request_pair",
202 "com.apple.mobile.lockdown.request_host_buid",
203 NULL
204 };
205 np_observe_notifications(np, spec);
206
207 usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid);
208 // TODO send notification to user's desktop
209 while (cbdata.np) {
210 sleep(1);
211 }
212
213 if (cbdata.np) {
214 np_client_free(cbdata.np);
215 }
216 } else {
217 // ============== iOS 6.x and below ==============
218 lerr = lockdownd_pair(lockdown, NULL);
219 if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
220 usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid);
221 // TODO send notification to user's desktop
222 goto leave;
223 } else if (lerr != LOCKDOWN_E_SUCCESS) {
224 usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
225 goto leave;
226 }
227
228 host_id = NULL;
229 userpref_device_record_get_host_id(dev->udid, &host_id);
230 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
231 free(host_id);
232 if (lerr != LOCKDOWN_E_SUCCESS) {
233 usbmuxd_log(LL_ERROR, "%s: ERROR StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr);
234 goto leave;
235 }
236
237 lerr = lockdownd_validate_pair(lockdown, NULL);
238 if (lerr != LOCKDOWN_E_SUCCESS) {
239 usbmuxd_log(LL_ERROR, "%s: ERROR: ValidatePair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
240 goto leave;
241 }
242
243 // make device visible
244 client_device_add(info);
245 }
246
247leave:
248 if (lockdown)
249 lockdownd_client_free(lockdown);
250 if (dev)
251 idevice_free(dev);
252
253 free(info);
254
255 return NULL;
256}
257#endif
258
259void preflight_worker_device_add(struct device_info* info)
260{
261#ifdef HAVE_LIBIMOBILEDEVICE
262 struct device_info *infocopy = (struct device_info*)malloc(sizeof(struct device_info));
263
264 memcpy(infocopy, info, sizeof(struct device_info));
265
266 pthread_t th;
267 pthread_create(&th, NULL, preflight_worker_handle_device_add, infocopy);
268#else
269 client_device_add(info);
270#endif
271}