diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 304 |
1 files changed, 243 insertions, 61 deletions
@@ -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 |