Unix domain sockets support.

The socket is not removed on shutdown, but the rest seems to work.
This commit is contained in:
Witold Filipczyk 2015-07-01 13:06:04 +02:00
parent 8f38e7873b
commit 4d8ec30100
3 changed files with 93 additions and 0 deletions

View file

@ -52,7 +52,9 @@
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
@ -138,8 +140,13 @@ int x_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
#define poll x_poll
#endif
char unixDomainSocket[UNIX_PATH_MAX];
time_t currentTime;
int unixDomainUser;
int unixDomainGroup;
int unixDomainChmod;
struct PayLoad {
int (*handler)(struct HttpConnection *, void *, const char *, int);
void *arg;
@ -283,6 +290,38 @@ void initServer(struct Server *server, int localhostOnly, int portMin,
server->numConnections = 0;
int true = 1;
if (unixDomainSocket[0]) {
server->serverFd = socket(AF_UNIX, SOCK_STREAM, 0);
check(server->serverFd >= 0);
check(!setsockopt(server->serverFd, SOL_SOCKET, SO_REUSEADDR,
&true, sizeof(true)));
struct sockaddr_un serverAddr = { 0 };
unlink(unixDomainSocket);
serverAddr.sun_family = AF_UNIX;
strcpy(serverAddr.sun_path, unixDomainSocket);
int servlen = sizeof(serverAddr.sun_family) + strlen(unixDomainSocket);
if (bind(server->serverFd, (struct sockaddr *)&serverAddr, servlen)) {
fatal("Failed to bind to unix socket");
}
check(!chown(unixDomainSocket, unixDomainUser, unixDomainGroup));
check(!chmod(unixDomainSocket, unixDomainChmod));
check(!listen(server->serverFd, SOMAXCONN));
check(server->pollFds = malloc(sizeof(struct pollfd)));
server->pollFds->fd = server->serverFd;
server->pollFds->events = POLLIN;
initTrie(&server->handlers, serverDestroyHandlers, NULL);
serverRegisterStreamingHttpHandler(server, "/quit", serverQuitHandler, NULL);
initSSL(&server->ssl);
return;
}
server->serverFd = socket(PF_INET, SOCK_STREAM, 0);
check(server->serverFd >= 0);
check(!setsockopt(server->serverFd, SOL_SOCKET, SO_REUSEADDR,
@ -347,6 +386,8 @@ void destroyServer(struct Server *server) {
free(server->pollFds);
destroyTrie(&server->handlers);
destroySSL(&server->ssl);
if (unixDomainSocket[0]) unlink(unixDomainSocket);
}
}

View file

@ -52,6 +52,15 @@
#include "libhttp/http.h"
#include "libhttp/ssl.h"
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 108
#endif
extern int unixDomainUser;
extern int unixDomainGroup;
extern int unixDomainChmod;
extern char unixDomainSocket[UNIX_PATH_MAX];
struct Server;
struct ServerConnection {

View file

@ -61,6 +61,9 @@
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#ifdef HAVE_SYS_PRCTL_H
@ -68,6 +71,7 @@
#endif
#include "libhttp/http.h"
#include "libhttp/server.h"
#include "logging/logging.h"
#include "shellinabox/externalfile.h"
#include "shellinabox/launcher.h"
@ -785,6 +789,7 @@ static void usage(void) {
" -s, --service=SERVICE define one or more services\n"
"%s"
" -q, --quiet turn off all messages\n"
" --unixdomain-only=PATH:USER:GROUP:CHMOD listen on unix socket\n"
" -u, --user=UID switch to this user (default: %s)\n"
" --user-css=STYLES defines user-selectable CSS options\n"
" -v, --verbose enable logging messages\n"
@ -891,6 +896,7 @@ static void parseArgs(int argc, char * const argv[]) {
{ "disable-ssl", 0, 0, 't' },
{ "disable-ssl-menu", 0, 0, 0 },
{ "quiet", 0, 0, 'q' },
{ "unixdomain-only", 1, 0, 0, },
{ "user", 1, 0, 'u' },
{ "user-css", 1, 0, 0 },
{ "verbose", 0, 0, 'v' },
@ -1126,6 +1132,43 @@ static void parseArgs(int argc, char * const argv[]) {
}
verbosity = MSG_QUIET;
logSetLogLevel(verbosity);
} else if (!idx--) {
// Unix domain only
if (!optarg || !*optarg) {
fatal("Option \"--unixdomain-only\" expects an argument.");
}
char *ptr, *s, *tmp;
s = optarg;
ptr = strchr(s, ':');
if (ptr == NULL) {
fatal("Syntax error in unixdomain-only definition \"%s\".", optarg);
}
check(ptr - s < UNIX_PATH_MAX);
memcpy(unixDomainSocket, s, ptr - s);
unixDomainSocket[ptr - s] = '\000';
s = ptr + 1;
ptr = strchr(s, ':');
if (ptr == NULL) {
fatal("Syntax error in unixdomain-only definition \"%s\".", optarg);
}
check(tmp = strndup(s, ptr - s));
unixDomainUser = parseUserArg(tmp, NULL);
free(tmp);
s = ptr + 1;
ptr = strchr(s, ':');
if (ptr == NULL) {
fatal("Syntax error in unixdomain-only definition \"%s\".", optarg);
}
check(tmp = strndup(s, ptr - s));
unixDomainGroup = parseGroupArg(tmp, NULL);
free(tmp);
s = ptr + 1;
unixDomainChmod = strtol(s, NULL, 0);
} else if (!idx--) {
// User
if (runAsUser >= 0) {