summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2013-09-19 07:45:02 +0200
committerGravatar Nikias Bassen2013-09-19 07:45:02 +0200
commitf631e8e055dfcdae440631902ed8a38eb5109cb8 (patch)
treeeeac77f6fef5eea8399160dc2ca1cb001ecfc338
parent23bcddf12b520f613451705e3f85c38c40333a90 (diff)
downloadusbmuxd-f631e8e055dfcdae440631902ed8a38eb5109cb8.tar.gz
usbmuxd-f631e8e055dfcdae440631902ed8a38eb5109cb8.tar.bz2
added preflight worker implementation to handle initial device pairing
-rw-r--r--configure.ac30
-rw-r--r--src/Makefile.am5
-rw-r--r--src/client.c1
-rw-r--r--src/device.c19
-rw-r--r--src/device.h2
-rw-r--r--src/main.c20
-rw-r--r--src/preflight.c271
-rw-r--r--src/preflight.h28
8 files changed, 365 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index a874692..b7aa54b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,6 +18,8 @@ AC_PROG_LIBTOOL
# Checks for libraries.
PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.3)
PKG_CHECK_MODULES(libplist, libplist >= 1.9, have_plist=yes, have_plist=no)
+PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.1.6, have_limd=yes, have_limd=no)
+AC_CHECK_LIB(pthread, [pthread_create, pthread_mutex_lock], [AC_SUBST(libpthread_LIBS,[-lpthread])], [AC_MSG_ERROR([libpthread is required to build usbmuxd])])
AC_ARG_WITH([protov1],
[AS_HELP_STRING([--without-protov1],
@@ -40,6 +42,27 @@ else
fi
fi
+AC_ARG_WITH([preflight],
+ [AS_HELP_STRING([--without-preflight],
+ [do not build with preflight worker support (default is yes)])],
+ [with_preflight=no],
+ [with_preflight=yes])
+
+if test "x$have_limd" = "xyes"; then
+ if test "x$with_preflight" != "xyes"; then
+ have_limd=no
+ echo "*** Note: preflight worker support has been disabled ***"
+ else
+ AC_DEFINE(HAVE_LIBIMOBILEDEVICE, 1, [Define if you have libimobiledevice support])
+ AC_SUBST(libimobiledevice_CFLAGS)
+ AC_SUBST(libimobiledevice_LIBS)
+ fi
+else
+ if test "x$with_preflight" == "xyes"; then
+ AC_MSG_ERROR([preflight worker support requested but libimobiledevice could not befound])
+ fi
+fi
+
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
@@ -73,7 +96,7 @@ case ${host_os} in
esac
AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
-AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter")
+AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-g -Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter")
AC_SUBST(GLOBAL_CFLAGS)
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
@@ -88,8 +111,9 @@ echo "
Configuration for $PACKAGE $VERSION:
-------------------------------------------
- Install prefix: .........: $prefix
- Protocol v1 support: ....: $have_plist
+ Install prefix: ...........: $prefix
+ Protocol v1 support: ......: $have_plist
+ Preflight worker support ..: $have_limd
Now type 'make' to build $PACKAGE $VERSION,
and then 'make install' for installation.
diff --git a/src/Makefile.am b/src/Makefile.am
index ae8fee7..883f1d8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,10 +1,11 @@
-AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS)
-AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS)
+AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS) $(libimobildevice_CFLAGS)
+AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) $(libimobiledevice_LIBS) $(libpthread_LIBS)
sbin_PROGRAMS = usbmuxd
usbmuxd_SOURCES = client.c client.h \
device.c device.h \
+ preflight.c preflight.h \
log.c log.h \
usb-linux.c usb.h \
utils.c utils.h \
diff --git a/src/client.c b/src/client.c
index d4a4a10..b2e3644 100644
--- a/src/client.c
+++ b/src/client.c
@@ -584,6 +584,7 @@ void client_process(int fd, short events)
void client_device_add(struct device_info *dev)
{
usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial);
+ device_set_visible(dev->id);
FOREACH(struct mux_client *client, &client_list) {
if(client->state == CLIENT_LISTEN)
notify_device_add(client, dev);
diff --git a/src/device.c b/src/device.c
index 91712be..27e25d5 100644
--- a/src/device.c
+++ b/src/device.c
@@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include <inttypes.h>
#include "device.h"
#include "client.h"
+#include "preflight.h"
#include "usb.h"
#include "log.h"
@@ -106,6 +107,7 @@ struct mux_device
struct usb_device *usbdev;
int id;
enum mux_dev_state state;
+ int visible;
struct collection connections;
uint16_t next_sport;
unsigned char *pktbuf;
@@ -461,7 +463,7 @@ static void device_version_input(struct mux_device *dev, struct version_header *
info.location = usb_get_location(dev->usbdev);
info.serial = usb_get_serial(dev->usbdev);
info.pid = usb_get_pid(dev->usbdev);
- client_device_add(&info);
+ preflight_worker_device_add(&info);
}
static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length)
@@ -642,6 +644,7 @@ int device_add(struct usb_device *usbdev)
dev->id = id;
dev->usbdev = usbdev;
dev->state = MUXDEV_INIT;
+ dev->visible = 0;
dev->next_sport = 1;
dev->pktbuf = malloc(DEV_MRU);
dev->pktlen = 0;
@@ -680,11 +683,21 @@ void device_remove(struct usb_device *usbdev)
usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
}
+void device_set_visible(int device_id)
+{
+ FOREACH(struct mux_device *dev, &device_list) {
+ if(dev->id == device_id) {
+ dev->visible = 1;
+ break;
+ }
+ } ENDFOREACH
+}
+
int device_get_count(void)
{
int count = 0;
FOREACH(struct mux_device *dev, &device_list) {
- if(dev->state == MUXDEV_ACTIVE)
+ if((dev->state == MUXDEV_ACTIVE) && dev->visible)
count++;
} ENDFOREACH
return count;
@@ -694,7 +707,7 @@ int device_get_list(struct device_info *p)
{
int count = 0;
FOREACH(struct mux_device *dev, &device_list) {
- if(dev->state == MUXDEV_ACTIVE) {
+ if((dev->state == MUXDEV_ACTIVE) && dev->visible) {
p->id = dev->id;
p->serial = usb_get_serial(dev->usbdev);
p->location = usb_get_location(dev->usbdev);
diff --git a/src/device.h b/src/device.h
index ea77069..4b1a581 100644
--- a/src/device.h
+++ b/src/device.h
@@ -40,6 +40,8 @@ int device_start_connect(int device_id, uint16_t port, struct mux_client *client
void device_client_process(int device_id, struct mux_client *client, short events);
void device_abort_connect(int device_id, struct mux_client *client);
+void device_set_visible(int device_id);
+
int device_get_count(void);
int device_get_list(struct device_info *p);
diff --git a/src/main.c b/src/main.c
index 32c6a2b..1804c30 100644
--- a/src/main.c
+++ b/src/main.c
@@ -49,6 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
static const char *socket_path = "/var/run/usbmuxd";
static const char *lockfile = "/var/run/usbmuxd.pid";
+static const char *userprefdir = "/var/lib/lockdown";
int should_exit;
int should_discover;
@@ -285,9 +286,6 @@ static int daemonize(void)
close(pfd[0]);
report_to_parent = 1;
- // Change the file mode mask
- umask(0);
-
// Create a new SID for the child process
sid = setsid();
if (sid < 0) {
@@ -531,6 +529,13 @@ int main(int argc, char *argv[])
if(listenfd < 0)
goto terminate;
+ struct stat fst;
+ int userprefdir_created = 0;
+ if (stat(userprefdir, &fst) < 0) {
+ mkdir(userprefdir, 0775);
+ userprefdir_created = 1;
+ }
+
// drop elevated privileges
if (drop_privileges && (getuid() == 0 || geteuid() == 0)) {
struct passwd *pw;
@@ -548,6 +553,15 @@ int main(int argc, char *argv[])
if (pw->pw_uid == 0) {
usbmuxd_log(LL_INFO, "Not dropping privileges to root");
} else {
+ if (userprefdir_created) {
+ if (chown(userprefdir, pw->pw_uid, pw->pw_gid) < 0) {
+ usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed", userprefdir, pw->pw_uid, pw->pw_gid);
+ }
+ if (chmod(userprefdir, 02775) < 0) {
+ usbmuxd_log(LL_WARNING, "chmod %s failed", userprefdir);
+ }
+ }
+
if ((res = initgroups(drop_user, pw->pw_gid)) < 0) {
usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set supplementary groups)");
goto terminate;
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 @@
+/*
+ usbmuxd - iPhone/iPod Touch USB multiplex server daemon
+
+Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 or version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pthread.h>
+
+#include <sys/time.h>
+
+#include <libimobiledevice/libimobiledevice.h>
+#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/notification_proxy.h>
+
+#include "preflight.h"
+#include "client.h"
+#include "log.h"
+
+#ifdef HAVE_LIBIMOBILEDEVICE
+enum connection_type {
+ CONNECTION_USBMUXD = 1
+};
+
+struct idevice_private {
+ char *udid;
+ enum connection_type conn_type;
+ void *conn_data;
+};
+
+extern void userpref_get_system_buid(char **systembuid);
+
+struct np_cb_data {
+ idevice_t dev;
+ np_client_t np;
+};
+
+static void set_untrusted_host_buid(lockdownd_client_t lockdown)
+{
+ char* system_buid = NULL;
+ userpref_get_system_buid(&system_buid);
+ usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid);
+ lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid));
+ free(system_buid);
+}
+
+static void np_callback(const char* notification, void* userdata)
+{
+ struct np_cb_data *cbdata = (struct np_cb_data*)userdata;
+ idevice_t dev = cbdata->dev;
+ struct idevice_private *_dev = (struct idevice_private*)dev;
+
+ lockdownd_client_t lockdown = NULL;
+ lockdownd_error_t lerr;
+
+ if (strlen(notification) == 0) {
+ cbdata->np = NULL;
+ return;
+ }
+
+ if (strcmp(notification, "com.apple.mobile.lockdown.request_pair") == 0) {
+ usbmuxd_log(LL_INFO, "%s: user trusted this computer on device %s, pairing now", __func__, _dev->udid);
+ 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);
+ return;
+ }
+
+ lerr = lockdownd_pair(lockdown, NULL);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ lockdownd_client_free(lockdown);
+ return;
+ }
+ lockdownd_client_free(lockdown);
+ // device will reconnect by itself at this point.
+
+ } else if (strcmp(notification, "com.apple.mobile.lockdown.request_host_buid") == 0) {
+ lerr = lockdownd_client_new(cbdata->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);
+ } else {
+ set_untrusted_host_buid(lockdown);
+ lockdownd_client_free(lockdown);
+ }
+ }
+}
+
+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;
+ lockdownd_error_t lerr;
+
+ 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
+ client_device_add(info);
+ goto leave;
+ }
+
+ char *host_id = NULL;
+ userpref_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_INFO, "%s: StartSession success for 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);
+ if (lerr == LOCKDOWN_E_INVALID_HOST_ID) {
+ usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid);
+ }
+
+ plist_t value = NULL;
+ 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;
+ }
+
+ char* version_str = NULL;
+ 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 beyond =============
+ usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid);
+
+ set_untrusted_host_buid(lockdown);
+
+ 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 np_cb_data cbdata;
+ cbdata.dev = dev;
+ cbdata.np = np;
+
+ np_set_notify_callback(np, np_callback, (void*)&cbdata);
+
+ const char* spec[] = {
+ "com.apple.mobile.lockdown.request_pair",
+ "com.apple.mobile.lockdown.request_host_buid",
+ NULL
+ };
+ np_observe_notifications(np, spec);
+
+ usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid);
+ // TODO send notification to user's desktop
+ while (cbdata.np) {
+ sleep(1);
+ }
+
+ if (cbdata.np) {
+ np_client_free(cbdata.np);
+ }
+ } else {
+ // ============== iOS 6.x and below ==============
+ lerr = lockdownd_pair(lockdown, NULL);
+ 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
+ goto leave;
+ } else if (lerr != LOCKDOWN_E_SUCCESS) {
+ usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ goto leave;
+ }
+
+ host_id = NULL;
+ userpref_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;
+ }
+
+ // make device visible
+ client_device_add(info);
+ }
+
+leave:
+ if (lockdown)
+ lockdownd_client_free(lockdown);
+ if (dev)
+ idevice_free(dev);
+
+ free(info);
+
+ return NULL;
+}
+#endif
+
+void preflight_worker_device_add(struct device_info* info)
+{
+#ifdef HAVE_LIBIMOBILEDEVICE
+ struct device_info *infocopy = (struct device_info*)malloc(sizeof(struct device_info));
+
+ memcpy(infocopy, info, sizeof(struct device_info));
+
+ pthread_t th;
+ pthread_create(&th, NULL, preflight_worker_handle_device_add, infocopy);
+#else
+ client_device_add(info);
+#endif
+}
diff --git a/src/preflight.h b/src/preflight.h
new file mode 100644
index 0000000..dce3356
--- /dev/null
+++ b/src/preflight.h
@@ -0,0 +1,28 @@
+/*
+ usbmuxd - iPhone/iPod Touch USB multiplex server daemon
+
+Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 or version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#ifndef __PREFLIGHT_H__
+#define __PREFLIGHT_H__
+
+#include "device.h"
+
+void preflight_worker_device_add(struct device_info* info);
+
+#endif