diff options
Diffstat (limited to 'src/preflight.c')
| -rw-r--r-- | src/preflight.c | 271 |
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 | |||
| 4 | Copyright (C) 2013 Nikias Bassen <nikias@gmx.li> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 2 or version 3. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program; if not, write to the Free Software | ||
| 17 | Foundation, 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 | ||
| 42 | enum connection_type { | ||
| 43 | CONNECTION_USBMUXD = 1 | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct idevice_private { | ||
| 47 | char *udid; | ||
| 48 | enum connection_type conn_type; | ||
| 49 | void *conn_data; | ||
| 50 | }; | ||
| 51 | |||
| 52 | extern void userpref_get_system_buid(char **systembuid); | ||
| 53 | |||
| 54 | struct np_cb_data { | ||
| 55 | idevice_t dev; | ||
| 56 | np_client_t np; | ||
| 57 | }; | ||
| 58 | |||
| 59 | static 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 | |||
| 68 | static 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 | |||
| 110 | static 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 | |||
| 247 | leave: | ||
| 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 | |||
| 259 | void 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 | } | ||
