summaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c304
1 files changed, 243 insertions, 61 deletions
diff --git a/src/main.c b/src/main.c
index aede710..8702a4b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,7 +1,7 @@
/*
* main.c
*
- * Copyright (C) 2009-2019 Nikias Bassen <nikias@gmx.li>
+ * Copyright (C) 2009-2021 Nikias Bassen <nikias@gmx.li>
* Copyright (C) 2013-2014 Martin Szulecki <m.szulecki@libimobiledevice.org>
* Copyright (C) 2009 Hector Martin <hector@marcansoft.com>
* Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
@@ -36,6 +36,9 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -51,12 +54,16 @@
#include "conf.h"
static const char *socket_path = "/var/run/usbmuxd";
-static const char *lockfile = "/var/run/usbmuxd.pid";
+#define DEFAULT_LOCKFILE "/var/run/usbmuxd.pid"
+static const char *lockfile = DEFAULT_LOCKFILE;
+// Global state used in other files
int should_exit;
int should_discover;
int use_logfile = 0;
+int no_preflight = 0;
+// Global state for main.c
static int verbose = 0;
static int foreground = 0;
static int drop_privileges = 0;
@@ -66,22 +73,162 @@ static int opt_enable_exit = 0;
static int opt_exit = 0;
static int exit_signal = 0;
static int daemon_pipe;
+static const char *listen_addr = NULL;
static int report_to_parent = 0;
-static int create_socket(void) {
- struct sockaddr_un bind_addr;
+static int create_socket(void)
+{
int listenfd;
+ const char* socket_addr = socket_path;
+ const char* tcp_port;
+ char listen_addr_str[256];
+
+ if (listen_addr) {
+ socket_addr = listen_addr;
+ }
+ tcp_port = strrchr(socket_addr, ':');
+ if (tcp_port) {
+ tcp_port++;
+ size_t nlen = tcp_port - socket_addr;
+ char* hostname = malloc(nlen);
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int yes = 1;
+ int res;
+
+ strncpy(hostname, socket_addr, nlen-1);
+ hostname[nlen-1] = '\0';
+
+ memset(&hints, '\0', sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ res = getaddrinfo(hostname, tcp_port, &hints, &result);
+ free(hostname);
+ if (res != 0) {
+ usbmuxd_log(LL_FATAL, "%s: getaddrinfo() failed: %s\n", __func__, gai_strerror(res));
+ return -1;
+ }
- if(unlink(socket_path) == -1 && errno != ENOENT) {
- usbmuxd_log(LL_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno));
- return -1;
- }
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (listenfd == -1) {
+ listenfd = -1;
+ continue;
+ }
- listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (listenfd == -1) {
- usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
- return -1;
+ if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+
+#ifdef SO_NOSIGPIPE
+ if (setsockopt(listenfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+#endif
+
+#if defined(AF_INET6) && defined(IPV6_V6ONLY)
+ if (rp->ai_family == AF_INET6) {
+ if (setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt() IPV6_V6ONLY: %s", __func__, strerror(errno));
+ }
+ }
+#endif
+
+ if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) < 0) {
+ usbmuxd_log(LL_FATAL, "%s: bind() failed: %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+
+ const void *addrdata = NULL;
+ if (rp->ai_family == AF_INET) {
+ addrdata = &((struct sockaddr_in*)rp->ai_addr)->sin_addr;
+ }
+#ifdef AF_INET6
+ else if (rp->ai_family == AF_INET6) {
+ addrdata = &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
+ }
+#endif
+ if (addrdata) {
+ char* endp = NULL;
+ uint16_t listen_port = 0;
+ if (rp->ai_family == AF_INET) {
+ listen_port = ntohs(((struct sockaddr_in*)rp->ai_addr)->sin_port);
+ if (inet_ntop(AF_INET, addrdata, listen_addr_str, sizeof(listen_addr_str)-6)) {
+ endp = &listen_addr_str[0] + strlen(listen_addr_str);
+ }
+ }
+#ifdef AF_INET6
+ else if (rp->ai_family == AF_INET6) {
+ listen_port = ntohs(((struct sockaddr_in6*)rp->ai_addr)->sin6_port);
+ listen_addr_str[0] = '[';
+ if (inet_ntop(AF_INET6, addrdata, listen_addr_str+1, sizeof(listen_addr_str)-8)) {
+ endp = &listen_addr_str[0] + strlen(listen_addr_str);
+ }
+ if (endp) {
+ *endp = ']';
+ endp++;
+ }
+ }
+#endif
+ if (endp) {
+ sprintf(endp, ":%u", listen_port);
+ }
+ }
+ break;
+ }
+ freeaddrinfo(result);
+ if (listenfd == -1) {
+ usbmuxd_log(LL_FATAL, "%s: Failed to create listening socket", __func__);
+ return -1;
+ }
+ } else {
+ struct sockaddr_un bind_addr;
+
+ if (strcmp(socket_addr, socket_path) != 0) {
+ struct stat fst;
+ if (stat(socket_addr, &fst) == 0) {
+ if (!S_ISSOCK(fst.st_mode)) {
+ usbmuxd_log(LL_FATAL, "FATAL: File '%s' already exists and is not a socket file. Refusing to continue.", socket_addr);
+ return -1;
+ }
+ }
+ }
+
+ if (unlink(socket_addr) == -1 && errno != ENOENT) {
+ usbmuxd_log(LL_FATAL, "%s: unlink(%s) failed: %s", __func__, socket_addr, strerror(errno));
+ return -1;
+ }
+
+ listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (listenfd == -1) {
+ usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ bzero(&bind_addr, sizeof(bind_addr));
+ bind_addr.sun_family = AF_UNIX;
+ strncpy(bind_addr.sun_path, socket_addr, sizeof(bind_addr.sun_path));
+ bind_addr.sun_path[sizeof(bind_addr.sun_path) - 1] = '\0';
+
+ if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
+ usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
+ return -1;
+ }
+ chmod(socket_addr, 0666);
+
+ snprintf(listen_addr_str, sizeof(listen_addr_str), "%s", socket_addr);
}
int flags = fcntl(listenfd, F_GETFL, 0);
@@ -93,21 +240,13 @@ static int create_socket(void) {
}
}
- bzero(&bind_addr, sizeof(bind_addr));
- bind_addr.sun_family = AF_UNIX;
- strcpy(bind_addr.sun_path, socket_path);
- if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
- usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
- return -1;
- }
-
// Start listening
- if (listen(listenfd, 5) != 0) {
+ if (listen(listenfd, 256) != 0) {
usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno));
return -1;
}
- chmod(socket_path, 0666);
+ usbmuxd_log(LL_INFO, "Listening on %s", listen_addr_str);
return listenfd;
}
@@ -151,7 +290,7 @@ static void set_signal_handlers(void)
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigprocmask(SIG_SETMASK, &set, NULL);
-
+
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handle_signal;
sigaction(SIGINT, &sa, NULL);
@@ -359,7 +498,10 @@ static int notify_parent(int status)
static void usage()
{
printf("Usage: %s [OPTIONS]\n", PACKAGE_NAME);
- printf("Expose a socket to multiplex connections from and to iOS devices.\n\n");
+ printf("\n");
+ printf("Expose a socket to multiplex connections from and to iOS devices.\n");
+ printf("\n");
+ printf("OPTIONS:\n");
printf(" -h, --help\t\tPrint this message.\n");
printf(" -v, --verbose\t\tBe verbose (use twice or more to increase).\n");
printf(" -f, --foreground\tDo not daemonize (implies one -v).\n");
@@ -368,12 +510,18 @@ static void usage()
printf(" \tStarting another instance will trigger discovery instead.\n");
printf(" -z, --enable-exit\tEnable \"--exit\" request from other instances and exit\n");
printf(" \tautomatically if no device is attached.\n");
+ printf(" -p, --no-preflight\tDisable lockdownd preflight on new device.\n");
#ifdef HAVE_UDEV
printf(" -u, --udev\t\tRun in udev operation mode (implies -n and -z).\n");
#endif
#ifdef HAVE_SYSTEMD
printf(" -s, --systemd\t\tRun in systemd operation mode (implies -z and -f).\n");
#endif
+ printf(" -S, --socket ADDR:PORT | PATH Specify source ADDR and PORT or a UNIX\n");
+ printf(" \t\tsocket PATH to use for the listening socket.\n");
+ printf(" \t\tDefault: %s\n", socket_path);
+ printf(" -P, --pidfile PATH\tSpecify a different location for the pid file, or pass\n");
+ printf(" \t\tNONE to disable. Default: %s\n", DEFAULT_LOCKFILE);
printf(" -x, --exit\t\tNotify a running instance to exit if there are no devices\n");
printf(" \t\tconnected (sends SIGUSR1 to running instance) and exit.\n");
printf(" -X, --force-exit\tNotify a running instance to exit even if there are still\n");
@@ -381,6 +529,8 @@ static void usage()
printf(" -l, --logfile=LOGFILE\tLog (append) to LOGFILE instead of stderr or syslog.\n");
printf(" -V, --version\t\tPrint version information and exit.\n");
printf("\n");
+ printf("Homepage: <" PACKAGE_URL ">\n");
+ printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
}
static void parse_opts(int argc, char **argv)
@@ -392,12 +542,15 @@ static void parse_opts(int argc, char **argv)
{"user", required_argument, NULL, 'U'},
{"disable-hotplug", no_argument, NULL, 'n'},
{"enable-exit", no_argument, NULL, 'z'},
+ {"no-preflight", no_argument, NULL, 'p'},
#ifdef HAVE_UDEV
{"udev", no_argument, NULL, 'u'},
#endif
#ifdef HAVE_SYSTEMD
{"systemd", no_argument, NULL, 's'},
#endif
+ {"socket", required_argument, NULL, 'S'},
+ {"pidfile", required_argument, NULL, 'P'},
{"exit", no_argument, NULL, 'x'},
{"force-exit", no_argument, NULL, 'X'},
{"logfile", required_argument, NULL, 'l'},
@@ -407,11 +560,11 @@ static void parse_opts(int argc, char **argv)
int c;
#ifdef HAVE_SYSTEMD
- const char* opts_spec = "hfvVuU:xXsnzl:";
+ const char* opts_spec = "hfvVuU:xXsnzl:pS:P:";
#elif HAVE_UDEV
- const char* opts_spec = "hfvVuU:xXnzl:";
+ const char* opts_spec = "hfvVuU:xXnzl:pS:P:";
#else
- const char* opts_spec = "hfvVU:xXnzl:";
+ const char* opts_spec = "hfvVU:xXnzl:pS:P:";
#endif
while (1) {
@@ -437,6 +590,9 @@ static void parse_opts(int argc, char **argv)
drop_privileges = 1;
drop_user = optarg;
break;
+ case 'p':
+ no_preflight = 1;
+ break;
#ifdef HAVE_UDEV
case 'u':
opt_disable_hotplug = 1;
@@ -455,6 +611,26 @@ static void parse_opts(int argc, char **argv)
case 'z':
opt_enable_exit = 1;
break;
+ case 'S':
+ if (!*optarg || *optarg == '-') {
+ usbmuxd_log(LL_FATAL, "ERROR: --socket requires an argument");
+ usage();
+ exit(2);
+ }
+ listen_addr = optarg;
+ break;
+ case 'P':
+ if (!*optarg || *optarg == '-') {
+ usbmuxd_log(LL_FATAL, "ERROR: --pidfile requires an argument");
+ usage();
+ exit(2);
+ }
+ if (!strcmp(optarg, "NONE")) {
+ lockfile = NULL;
+ } else {
+ lockfile = optarg;
+ }
+ break;
case 'x':
opt_exit = 1;
exit_signal = SIGUSR1;
@@ -516,19 +692,21 @@ int main(int argc, char *argv[])
set_signal_handlers();
signal(SIGPIPE, SIG_IGN);
- res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644);
- if(res == -1) {
- usbmuxd_log(LL_FATAL, "Could not open lockfile");
- goto terminate;
- }
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- lock.l_pid = 0;
- fcntl(lfd, F_GETLK, &lock);
- close(lfd);
- if (lock.l_type != F_UNLCK) {
+ if (lockfile) {
+ res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644);
+ if(res == -1) {
+ usbmuxd_log(LL_FATAL, "Could not open lockfile");
+ goto terminate;
+ }
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = 0;
+ fcntl(lfd, F_GETLK, &lock);
+ close(lfd);
+ }
+ if (lockfile && lock.l_type != F_UNLCK) {
if (opt_exit) {
if (lock.l_pid && !kill(lock.l_pid, 0)) {
usbmuxd_log(LL_NOTICE, "Sending signal %d to instance with pid %d", exit_signal, lock.l_pid);
@@ -564,7 +742,9 @@ int main(int argc, char *argv[])
goto terminate;
}
}
- unlink(lockfile);
+ if (lockfile) {
+ unlink(lockfile);
+ }
if (opt_exit) {
usbmuxd_log(LL_NOTICE, "No running instance found, none killed. Exiting.");
@@ -579,26 +759,28 @@ int main(int argc, char *argv[])
}
}
- // now open the lockfile and place the lock
- res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
- if(res < 0) {
- usbmuxd_log(LL_FATAL, "Could not open lockfile");
- goto terminate;
- }
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) {
- usbmuxd_log(LL_FATAL, "Lockfile locking failed!");
- goto terminate;
- }
- sprintf(pids, "%d", getpid());
- if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) {
- usbmuxd_log(LL_FATAL, "Could not write pidfile!");
- if(res >= 0)
- res = -2;
- goto terminate;
+ if (lockfile) {
+ // now open the lockfile and place the lock
+ res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if(res < 0) {
+ usbmuxd_log(LL_FATAL, "Could not open pidfile '%s'", lockfile);
+ goto terminate;
+ }
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) {
+ usbmuxd_log(LL_FATAL, "Locking pidfile '%s' failed!", lockfile);
+ goto terminate;
+ }
+ sprintf(pids, "%d", getpid());
+ if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) {
+ usbmuxd_log(LL_FATAL, "Could not write pidfile!");
+ if(res >= 0)
+ res = -2;
+ goto terminate;
+ }
}
// set number of file descriptors to higher value