From: Martin Mares Date: Wed, 19 Jul 2017 09:22:03 +0000 (+0200) Subject: Initial commit: just playing... X-Git-Tag: v0.9~50 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=4f5fef0dd37416f78e208b06814d91ab6e2c7bc7;p=subauth.git Initial commit: just playing... --- 4f5fef0dd37416f78e208b06814d91ab6e2c7bc7 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fedb3da --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +# The default target +all: runtree programs configs + +# Include configuration +s=. +-include obj/config.mk +obj/config.mk: + @echo "You need to run configure first." && false + +# Do not show strange errors if the BUILDSYS is not set +# (it happens if noone called configure as reported above) +ifdef BUILDSYS + +# We will use the libucw build system +include $(BUILDSYS)/Maketop + +EXTRA_RUNDIRS=run + +# Add the detected flags to all the global flags +CFLAGS+=$(LIBUCW_CFLAGS) +LIBS+=$(LIBUCW_LIBS) + +# Programs we want to compile +PROGS+=$(o)/subauthd $(o)/subauth + +# And how they are created +$(o)/subauthd: $(o)/subauthd.o $(LIBUCW) +$(o)/subauth: $(o)/subauth.o $(LIBUCW) + +# Configuration files +CONFIGS+=subauthd + +# And finally the default rules of the build system +include $(BUILDSYS)/Makebottom + +endif diff --git a/configure b/configure new file mode 100755 index 0000000..3d741cd --- /dev/null +++ b/configure @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# Configure script for the sub-authentication daemon +# Inspired by LibUCW examples + +use warnings; +use strict; + +our($srcdir, $libdir); +BEGIN { + # Find the sources + my $pkgfile = "subauthd.c"; + if (!defined ($srcdir = $ENV{"SRCDIR"})) { + if (-f $pkgfile) { + $srcdir="."; + } elsif ($0 =~ m@^(.*)/configure$@ && -f "$1/$pkgfile") { + $srcdir=$1; + } else { + die "Don't know how to find myself. Please set SRCDIR manually.\n"; + } + } + # Ask pkg-config if libucw is installed and find its configure modules + `pkg-config libucw --atleast-version=3.13`; + !$? or die "Package `libucw' (version 3.13 or newer) not found. Is PKG_CONFIG_PATH set properly?\n"; + $libdir=`pkg-config libucw --variable=perl_modules_dir`; + chomp $libdir; + die "Unable to find the libucw configure system\n" if $? || not defined $libdir; +} +use lib $libdir; +use UCW::Configure; + +Init($srcdir, 'default.cfg'); +Log "### Configuring subauthd ###\n\n"; +Include Get("CONFIG"); +# What should be detected? +require UCW::Configure::Build; +require UCW::Configure::Paths; +require UCW::Configure::C; +require UCW::Configure::Pkg; + +# Get some libraries +UCW::Configure::Pkg::PkgConfig("libucw") or Fail("libUCW is required"); +Finish(); + +Log "\nConfigured, run `make' to build everything.\n"; diff --git a/default.cfg b/default.cfg new file mode 100644 index 0000000..f2062af --- /dev/null +++ b/default.cfg @@ -0,0 +1,4 @@ +# You can specify default configuration here: +# Set("SOME_SYMBOL"); + +1; diff --git a/subauth.c b/subauth.c new file mode 100644 index 0000000..cb64f94 --- /dev/null +++ b/subauth.c @@ -0,0 +1,53 @@ +/* + * Sub-authentication Client + * + * (c) 2017 Martin Mares + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "autoconf.h" + +static char *socket_path = INSTALL_RUN_DIR "/subauthd.socket"; + +static const struct opt_section options = { + OPT_ITEMS { + OPT_HELP("A client to the sub-authentication daemon."), + OPT_HELP("Usage: subauth [options]"), + OPT_HELP(""), + OPT_HELP("Options:"), + OPT_HELP_OPTION, + OPT_END + } +}; + +int main(int argc UNUSED, char **argv) +{ + opt_parse(&options, argv+1); + + int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (sk < 0) + die("socket(PF_UNIX, SOCK_SEQPACKET): %m"); + + struct sockaddr_un sun; + sun.sun_family = AF_UNIX; + if (strlen(socket_path) >= sizeof(sun.sun_path)) + die("Socket path too long"); + strcpy(sun.sun_path, socket_path); + + if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0) + die("Cannot connect to %s: %m", socket_path); + + char msg[] = "Brum!"; + if (send(sk, msg, sizeof(msg), 0) < 0) + die("Send failed: %m"); + + return 0; +} diff --git a/subauthd.c b/subauthd.c new file mode 100644 index 0000000..d8ee471 --- /dev/null +++ b/subauthd.c @@ -0,0 +1,227 @@ +/* + * Sub-authentication Daemon + * + * (c) 2017 Martin Mares + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "autoconf.h" + +static char *socket_path = "subauthd.socket"; +static uint max_connections = ~0U; + +static struct main_file listen_socket; +static uint num_connections; + +#define SOCKET_TIMEOUT 60000 // in ms +#define MAX_PACKET_SIZE 4096 +#define MAX_OOB_DATA_SIZE 4096 + +struct client { + struct main_file socket; + struct main_timer timer; +}; + +static byte packet_buffer[MAX_PACKET_SIZE]; +static byte oob_data_buffer[MAX_OOB_DATA_SIZE]; + +static void client_close(struct client *c) +{ + msg(L_INFO, "Closing connection"); + file_del(&c->socket); + timer_del(&c->timer); + close(c->socket.fd); +} + +static void socket_timeout_handler(struct main_timer *tm) +{ + struct client *c = tm->data; + + msg(L_INFO, "Client timeout"); + + client_close(c); +} + +static int socket_read_handler(struct main_file *fi) +{ + struct client *c = fi->data; + + struct iovec iov = { + .iov_base = packet_buffer, + .iov_len = MAX_PACKET_SIZE, + }; + + struct msghdr mh = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = oob_data_buffer, + .msg_controllen = MAX_OOB_DATA_SIZE, + }; + + ssize_t len = recvmsg(fi->fd, &mh, 0); + if (len < 0) + { + if (errno != EAGAIN && errno != EINTR) + msg(L_ERROR, "Socket read: %m"); + return HOOK_IDLE; + } + + if (!len) + { + client_close(c); + return HOOK_IDLE; + } + + msg(L_INFO, "Got packet: len=%zd", len); + + struct ucred *cred = NULL; + for (struct cmsghdr *cm = CMSG_FIRSTHDR(&mh); cm; cm = CMSG_NXTHDR(&mh, cm)) + { + if (cm->cmsg_level == SOL_SOCKET) + { + if (cm->cmsg_type == SCM_RIGHTS) + { + // We are not interested in receiving file descriptor, but despite + // that they could be attached to the message. If it happens, simply + // close them. + int *fdptr = (int *) CMSG_DATA(cm); + int nfd = cm->cmsg_len / sizeof(int); + for (int i=0; icmsg_type == SCM_CREDENTIALS) + { + ASSERT(cm->cmsg_len >= sizeof(cred)); + cred = (struct ucred *) CMSG_DATA(cm); + } + } + } + + if (!cred) + { + msg(L_ERROR, "Dropping message with no credentials"); + return HOOK_RETRY; + } + + msg(L_INFO, "Credentials: pid=%d uid=%d gid=%d", (int) cred->pid, (int) cred->uid, (int) cred->gid); + + return HOOK_RETRY; +} + +static int listen_read_handler(struct main_file *fi) +{ + struct sockaddr_un client; + socklen_t addr_len = sizeof(client); + + int new_sk = accept(fi->fd, &client, &addr_len); + if (new_sk < 0) + { + if (errno != EAGAIN && errno != EINTR) + msg(L_ERROR, "Socket accept: %m"); + return HOOK_IDLE; + } + + if (num_connections >= max_connections) + { + msg(L_WARN, "Too many connections (you might need to increase MaxConnections)"); + close(new_sk); + return HOOK_IDLE; + } + num_connections++; + + msg(L_INFO, "Accepted connection"); + + if (fcntl(new_sk, F_SETFL, fcntl(new_sk, F_GETFL) | O_NONBLOCK) < 0) + die("Cannot set O_NONBLOCK: %m"); + + struct client *c = xmalloc_zero(sizeof(*c)); + c->socket.fd = new_sk; + c->socket.read_handler = socket_read_handler; + c->socket.data = c; + file_add(&c->socket); + + c->timer.handler = socket_timeout_handler; + c->timer.data = c; + timer_add_rel(&c->timer, SOCKET_TIMEOUT); + + return HOOK_RETRY; +} + +static void init_socket(void) +{ + int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (sk < 0) + die("socket(PF_UNIX, SOCK_SEQPACKET): %m"); + + if (fcntl(sk, F_SETFL, fcntl(sk, F_GETFL) | O_NONBLOCK) < 0) + die("Cannot set O_NONBLOCK: %m"); + + struct sockaddr_un sun; + sun.sun_family = AF_UNIX; + if (strlen(socket_path) >= sizeof(sun.sun_path)) + die("SocketPath too long"); + strcpy(sun.sun_path, socket_path); + + if (unlink(socket_path) < 0 && errno != ENOENT) + die("Cannot unlink old socket %s: %m", socket_path); + + if (bind(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0) + die("Cannot bind to %s: %m", socket_path); + + if (listen(sk, 64) < 0) + die("listen(): %m"); + + int one; + if (setsockopt(sk, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) + die("setsockopt(SO_PASSCRED): %m"); + + listen_socket.fd = sk; + listen_socket.read_handler = listen_read_handler; + file_add(&listen_socket); + + msg(L_INFO, "Listening on %s", socket_path); +} + +static struct cf_section daemon_config = { + CF_ITEMS { + CF_STRING("SocketPath", &socket_path), + CF_UINT("MaxConnections", &max_connections), + CF_END + } +}; + +static const struct opt_section options = { + OPT_ITEMS { + OPT_HELP("A sub-authentication daemon."), + OPT_HELP("Usage: subauthd [options]"), + OPT_HELP(""), + OPT_HELP("Options:"), + OPT_HELP_OPTION, + OPT_CONF_OPTIONS, + OPT_END + } +}; + +int main(int argc UNUSED, char **argv) +{ + cf_def_file = CONFIG_DIR "/subauthd"; + cf_declare_section("SubauthD", &daemon_config, 0); + opt_parse(&options, argv+1); + + main_init(); + init_socket(); + + main_loop(); + return 0; +}