static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) { int res; usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag); if(client->state != CLIENT_COMMAND) { usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state", client->fd); if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; client_close(client); return -1; } if((hdr->version != 0) && (hdr->version != 1)) { usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); send_result(client, hdr->tag, RESULT_BADVERSION); return 0; } struct usbmuxd_connect_request *ch; char *payload; uint32_t payload_size; switch(hdr->message) { case MESSAGE_PLIST: client->proto_version = 1; payload = (char*)(hdr) + sizeof(struct usbmuxd_header); payload_size = hdr->length - sizeof(struct usbmuxd_header); plist_t dict = NULL; plist_from_xml(payload, payload_size, &dict); if (!dict) { usbmuxd_log(LL_ERROR, "Could not parse plist from payload!"); return -1; } else { char *message = NULL; plist_t node = plist_dict_get_item(dict, "MessageType"); plist_get_string_val(node, &message); if (!message) { usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!"); plist_free(dict); return -1; } if (!strcmp(message, "Listen")) { free(message); plist_free(dict); if (send_result(client, hdr->tag, 0) < 0) return -1; usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd); return start_listen(client); } else if (!strcmp(message, "Connect")) { uint64_t val; uint16_t portnum = 0; uint32_t device_id = 0; free(message); // get device id node = plist_dict_get_item(dict, "DeviceID"); if (!node) { usbmuxd_log(LL_ERROR, "Received connect request without device_id!"); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADDEV) < 0) return -1; return 0; } val = 0; plist_get_uint_val(node, &val); device_id = (uint32_t)val; // get port number node = plist_dict_get_item(dict, "PortNumber"); if (!node) { usbmuxd_log(LL_ERROR, "Received connect request without port number!"); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } val = 0; plist_get_uint_val(node, &val); portnum = (uint16_t)val; plist_free(dict); usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum)); res = device_start_connect(device_id, ntohs(portnum), client); if(res < 0) { if (send_result(client, hdr->tag, -res) < 0) return -1; } else { client->connect_tag = hdr->tag; client->connect_device = device_id; client->state = CLIENT_CONNECTING1; } return 0; } else if (!strcmp(message, "ListDevices")) { free(message); plist_free(dict); if (send_device_list(client, hdr->tag) < 0) return -1; return 0; } else if (!strcmp(message, "ReadBUID")) { free(message); plist_free(dict); if (send_system_buid(client, hdr->tag) < 0) return -1; return 0; } else if (!strcmp(message, "ReadPairRecord")) { free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); plist_free(dict); res = send_pair_record(client, hdr->tag, record_id); if (record_id) free(record_id); if (res < 0) return -1; return 0; } else if (!strcmp(message, "SavePairRecord")) { uint32_t rval = RESULT_OK; free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); char* record_data = NULL; uint64_t record_size = 0; plist_t rdata = plist_dict_get_item(dict, "PairRecordData"); if (rdata && plist_get_node_type(rdata) == PLIST_DATA) { plist_get_data_val(rdata, &record_data, &record_size); } plist_free(dict); if (record_id && record_data) { res = config_set_device_record(record_id, record_data, record_size); if (res < 0) { rval = -res; } free(record_id); } else { rval = EINVAL; } if (send_result(client, hdr->tag, rval) < 0) return -1; return 0; } else if (!strcmp(message, "DeletePairRecord")) { uint32_t rval = RESULT_OK; free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); plist_free(dict); if (record_id) { res = config_remove_device_record(record_id); if (res < 0) { rval = -res; } free(record_id); } else { rval = EINVAL; } if (send_result(client, hdr->tag, rval) < 0) return -1; return 0; } else { usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); free(message); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } } // should not be reached?! return -1; case MESSAGE_LISTEN: if(send_result(client, hdr->tag, 0) < 0) return -1; usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd); return start_listen(client); case MESSAGE_CONNECT: ch = (void*)hdr; usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, ch->device_id, ntohs(ch->port)); res = device_start_connect(ch->device_id, ntohs(ch->port), client); if(res < 0) { if(send_result(client, hdr->tag, -res) < 0) return -1; } else { client->connect_tag = hdr->tag; client->connect_device = ch->device_id; client->state = CLIENT_CONNECTING1; } return 0; default: usbmuxd_log(LL_ERROR, "Client %d invalid command %d", client->fd, hdr->message); if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } return -1; }
static void* preflight_worker_handle_device_add(void* userdata) { struct device_info *info = (struct device_info*)userdata; struct idevice_private *_dev = (struct idevice_private*)malloc(sizeof(struct idevice_private)); _dev->udid = strdup(info->serial); _dev->conn_type = CONNECTION_USBMUXD; _dev->conn_data = (void*)(long)info->id; idevice_t dev = (idevice_t)_dev; lockdownd_client_t lockdown = NULL; lockdownd_error_t lerr; plist_t value = NULL; char* version_str = NULL; usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid); retry: lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } char *type = NULL; lerr = lockdownd_query_type(lockdown, &type); if (!type) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get lockdownd type from device %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } if (strcmp(type, "com.apple.mobile.lockdown") != 0) { // make restore mode devices visible free(type); usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } free(type); int is_device_paired = 0; char *host_id = NULL; if (config_has_device_record(dev->udid)) { config_device_record_get_host_id(dev->udid, &host_id); lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); if (host_id) free(host_id); if (lerr == LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid); usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); } else { lerr = LOCKDOWN_E_INVALID_HOST_ID; } switch (lerr) { case LOCKDOWN_E_INVALID_HOST_ID: usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid); break; case LOCKDOWN_E_SSL_ERROR: usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid); if (config_remove_device_record(_dev->udid) == 0) { lockdownd_client_free(lockdown); lockdown = NULL; goto retry; } else { usbmuxd_log(LL_ERROR, "%s: Could not remove pair record for device %s", __func__, _dev->udid); } break; default: is_device_paired = 1; break; } lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } if (value && plist_get_node_type(value) == PLIST_STRING) { plist_get_string_val(value, &version_str); } if (!version_str) { usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data); goto leave; } int version_major = strtol(version_str, NULL, 10); if (version_major >= 7) { /* iOS 7.0 and later */ usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid); lockdownd_set_untrusted_host_buid(lockdown); /* if not paired, trigger the trust dialog to make sure it appears */ if (!is_device_paired) { if (lockdownd_pair(lockdown, NULL) == LOCKDOWN_E_SUCCESS) { /* if device is still showing the setup screen it will pair even without trust dialog */ usbmuxd_log(LL_INFO, "%s: Pair success for device %s", __func__, _dev->udid); usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } } lockdownd_service_descriptor_t service = NULL; lerr = lockdownd_start_service(lockdown, "com.apple.mobile.insecure_notification_proxy", &service); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not start insecure_notification_proxy on %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } np_client_t np = NULL; np_client_new(dev, service, &np); lockdownd_service_descriptor_free(service); service = NULL; lockdownd_client_free(lockdown); lockdown = NULL; struct cb_data cbdata; cbdata.dev = dev; cbdata.np = np; cbdata.is_device_connected = 1; np_set_notify_callback(np, np_callback, (void*)&cbdata); device_set_preflight_cb_data(info->id, (void*)&cbdata); const char* spec[] = { "com.apple.mobile.lockdown.request_pair", "com.apple.mobile.lockdown.request_host_buid", NULL }; np_observe_notifications(np, spec); /* TODO send notification to user's desktop */ usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid); /* make device visible anyways */ client_device_add(info); while (cbdata.np && cbdata.is_device_connected == 1) { sleep(1); } device_set_preflight_cb_data(info->id, NULL); usbmuxd_log(LL_INFO, "%s: Finished waiting for notification from device %s, is_device_connected %d", __func__, _dev->udid, cbdata.is_device_connected); if (cbdata.np) { np_client_free(cbdata.np); } } else { /* iOS 6.x and earlier */ lerr = lockdownd_pair(lockdown, NULL); if (lerr != LOCKDOWN_E_SUCCESS) { if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid); /* TODO send notification to user's desktop */ } else { usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); } usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); /* make device visible anyways */ client_device_add(info); goto leave; } host_id = NULL; config_device_record_get_host_id(dev->udid, &host_id); lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); free(host_id); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } lerr = lockdownd_validate_pair(lockdown, NULL); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: ValidatePair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); goto leave; } usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); /* emit device added event and thus make device visible to clients */ client_device_add(info); } leave: if (value) plist_free(value); if (version_str) free(version_str); if (lockdown) lockdownd_client_free(lockdown); if (dev) idevice_free(dev); free(info); return NULL; }