commit - e39d79e3c6d16ad1f982e9c9a8c2f99d368bd15c
commit + ff2b55acc0b4c0c704bfbafbb9ff1a74be3f49af
blob - 545a13d2e5aba6dc9df486f7300af0acf23c4df7
blob + 0505fbd1f8d0b37fded75218be702fa5b8fe4fab
--- gotwebd/Makefile
+++ gotwebd/Makefile
.include "Makefile.inc"
PROG = gotwebd
-SRCS = config.c sockets.c gotwebd.c parse.y \
+SRCS = auth.c config.c sockets.c gotwebd.c parse.y \
fcgi.c gotweb.c got_operations.c tmpl.c pages.c
SRCS += blame.c commit_graph.c delta.c diff.c \
diffreg.c error.c object.c object_cache.c \
blob - /dev/null
blob + c1c7d625060f9c5984c837f36bb35b671ad96ee9 (mode 644)
--- /dev/null
+++ gotwebd/auth.c
+/*
+ * Copyright (c) 2025 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <signal.h>
+#include <siphash.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "got_error.h"
+#include "got_reference.h"
+
+#include "gotwebd.h"
+#include "log.h"
+
+#define AUTH_SOCKET_BACKLOG 4
+
+struct gotwebd_auth_client {
+ TAILQ_ENTRY(gotwebd_auth_client) entry;
+ uint32_t id;
+ int fd;
+ uid_t euid;
+ struct imsgev iev;
+};
+TAILQ_HEAD(gotwebd_auth_clients, gotwebd_auth_client);
+
+static struct gotwebd_auth_clients clients[GOTWEBD_MAXCLIENTS * 4];
+static SIPHASH_KEY clients_hash_key;
+static volatile int client_cnt;
+static int inflight;
+
+static void
+clients_init(void)
+{
+ uint64_t slot;
+
+ arc4random_buf(&clients_hash_key, sizeof(clients_hash_key));
+
+ for (slot = 0; slot < nitems(clients); slot++)
+ TAILQ_INIT(&clients[slot]);
+}
+
+static uint64_t
+client_hash(uint32_t client_id)
+{
+ return SipHash24(&clients_hash_key, &client_id, sizeof(client_id));
+}
+
+static void
+add_client(struct gotwebd_auth_client *client)
+{
+ uint64_t slot = client_hash(client->id) % nitems(clients);
+ TAILQ_INSERT_HEAD(&clients[slot], client, entry);
+ client_cnt++;
+}
+
+static struct gotwebd_auth_client *
+find_client(uint32_t client_id)
+{
+ uint64_t slot;
+ struct gotwebd_auth_client *c;
+
+ slot = client_hash(client_id) % nitems(clients);
+ TAILQ_FOREACH(c, &clients[slot], entry) {
+ if (c->id == client_id)
+ return c;
+ }
+
+ return NULL;
+}
+
+static uint32_t
+get_client_id(void)
+{
+ int duplicate = 0;
+ uint32_t id;
+
+ do {
+ id = arc4random();
+ duplicate = (find_client(id) != NULL);
+ } while (duplicate || id == 0);
+
+ return id;
+}
+
+static int
+auth_socket_listen(struct gotwebd *env, struct socket *sock,
+ uid_t uid, gid_t gid)
+{
+ int u_fd = -1;
+ mode_t old_umask, mode;
+
+ u_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK| SOCK_CLOEXEC, 0);
+ if (u_fd == -1) {
+ log_warn("%s: socket", __func__);
+ return -1;
+ }
+
+ if (unlink(sock->conf.unix_socket_name) == -1) {
+ if (errno != ENOENT) {
+ log_warn("%s: unlink %s", __func__,
+ sock->conf.unix_socket_name);
+ close(u_fd);
+ return -1;
+ }
+ }
+
+ old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
+ mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+ if (bind(u_fd, (struct sockaddr *)&sock->conf.addr.ss,
+ sock->conf.addr.slen) == -1) {
+ log_warn("%s: bind: %s", __func__, sock->conf.unix_socket_name);
+ close(u_fd);
+ (void)umask(old_umask);
+ return -1;
+ }
+
+ (void)umask(old_umask);
+
+ if (chmod(sock->conf.unix_socket_name, mode) == -1) {
+ log_warn("%s: chmod", __func__);
+ close(u_fd);
+ (void)unlink(sock->conf.unix_socket_name);
+ return -1;
+ }
+
+ if (chown(sock->conf.unix_socket_name, uid, gid) == -1) {
+ log_warn("%s: chown", __func__);
+ close(u_fd);
+ (void)unlink(sock->conf.unix_socket_name);
+ return -1;
+ }
+
+ if (listen(u_fd, AUTH_SOCKET_BACKLOG) == -1) {
+ log_warn("%s: listen", __func__);
+ return -1;
+ }
+
+ return u_fd;
+}
+
+int
+auth_privinit(struct gotwebd *env, uid_t uid, gid_t gid)
+{
+ struct socket *sock = env->auth_sock;
+
+ if (sock == NULL)
+ fatalx("no authentication socket configured");
+
+ log_info("initializing authentication socket %s",
+ sock->conf.unix_socket_name);
+
+ sock->fd = auth_socket_listen(env, sock, uid, gid);
+ if (sock->fd == -1)
+ return -1;
+
+ return 0;
+}
+
+static void
+auth_shutdown(void)
+{
+ struct gotwebd *env = gotwebd_env;
+
+ imsgbuf_clear(&env->iev_parent->ibuf);
+ free(env->iev_parent);
+ if (env->iev_auth) {
+ imsgbuf_clear(&env->iev_auth->ibuf);
+ free(env->iev_auth);
+ }
+ free(env);
+
+ exit(0);
+}
+
+static void
+auth_sighdlr(int sig, short event, void *arg)
+{
+ switch (sig) {
+ case SIGHUP:
+ log_info("%s: ignoring SIGHUP", __func__);
+ break;
+ case SIGPIPE:
+ log_info("%s: ignoring SIGPIPE", __func__);
+ break;
+ case SIGUSR1:
+ log_info("%s: ignoring SIGUSR1", __func__);
+ break;
+ case SIGCHLD:
+ break;
+ case SIGINT:
+ case SIGTERM:
+ auth_shutdown();
+ break;
+ default:
+ log_warn("unexpected signal %d", sig);
+ break;
+ }
+}
+
+static int
+accept_reserve(int fd, struct sockaddr *addr, socklen_t *addrlen,
+ int reserve, volatile int *counter)
+{
+ int ret;
+
+ if (getdtablecount() + reserve +
+ ((*counter + 1) * FD_NEEDED) >= getdtablesize()) {
+ log_debug("inflight fds exceeded");
+ errno = EMFILE;
+ return -1;
+ }
+
+ if ((ret = accept4(fd, addr, addrlen,
+ SOCK_NONBLOCK | SOCK_CLOEXEC)) > -1) {
+ (*counter)++;
+ }
+
+ return ret;
+}
+
+static const struct got_error *
+disconnect(struct gotwebd_auth_client *client)
+{
+ uint64_t slot;
+ int client_fd;
+
+ log_debug("client on fd %d disconnecting", client->fd);
+
+ slot = client_hash(client->id) % nitems(clients);
+ TAILQ_REMOVE(&clients[slot], client, entry);
+
+ if (client->iev.ibuf.fd != -1)
+ imsgbuf_clear(&client->iev.ibuf);
+
+ client_fd = client->fd;
+ free(client);
+ inflight--;
+ client_cnt--;
+ if (close(client_fd) == -1)
+ return got_error_from_errno("close");
+
+ return NULL;
+}
+
+static void
+auth_request(int fd, short event, void *arg)
+{
+ log_warnx("%s", __func__);
+}
+
+static void
+auth_accept(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct gotwebd *env = gotwebd_env;
+ struct sockaddr_storage ss;
+ struct timeval backoff;
+ socklen_t len;
+ int s = -1;
+ struct gotwebd_auth_client *client = NULL;
+ uid_t euid;
+ gid_t egid;
+
+ backoff.tv_sec = 1;
+ backoff.tv_usec = 0;
+
+ if (event_add(&iev->ev, NULL) == -1) {
+ log_warn("event_add");
+ return;
+ }
+ if (event & EV_TIMEOUT)
+ return;
+
+ len = sizeof(ss);
+
+ /* Other backoff conditions apart from EMFILE/ENFILE? */
+ s = accept_reserve(fd, (struct sockaddr *)&ss, &len, FD_RESERVE,
+ &inflight);
+ if (s == -1) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+ case ECONNABORTED:
+ return;
+ case EMFILE:
+ case ENFILE:
+ event_del(&iev->ev);
+ evtimer_add(&env->auth_pause_ev, &backoff);
+ return;
+ default:
+ log_warn("accept");
+ return;
+ }
+ }
+
+ if (client_cnt >= GOTWEBD_MAXCLIENTS)
+ goto err;
+
+ if (getpeereid(s, &euid, &egid) == -1) {
+ log_warn("getpeerid");
+ goto err;
+ }
+
+ client = calloc(1, sizeof(*client));
+ if (client == NULL) {
+ log_warn("%s: calloc", __func__);
+ goto err;
+ }
+ client->iev.ibuf.fd = -1;
+ client->id = get_client_id();
+ client->fd = s;
+ client->euid = euid;
+ s = -1;
+
+ if (imsgbuf_init(&client->iev.ibuf, client->fd) == -1) {
+ log_warn("imsgbuf_init");
+ goto err;
+ }
+
+ client->iev.handler = auth_request;;
+ client->iev.data = client;
+ event_set(&client->iev.ev, client->fd, EV_READ, auth_request, client);
+ event_add(&client->iev.ev, NULL);
+
+ add_client(client);
+
+ log_debug("%s: new client connected on fd %d uid %d gid %d", __func__,
+ client->fd, euid, egid);
+ return;
+err:
+ inflight--;
+ if (client)
+ disconnect(client);
+ if (s != -1)
+ close(s);
+}
+
+
+static void
+get_auth_sock(struct gotwebd *env, struct imsg *imsg)
+{
+ const struct got_error *err;
+ struct imsgev *iev;
+ int fd;
+
+ if (env->iev_auth != NULL) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ fatalx("%s", err->msg);
+ }
+
+ if (IMSG_DATA_SIZE(imsg) != 0) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ fatalx("%s", err->msg);
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1) {
+ err = got_error(GOT_ERR_PRIVSEP_NO_FD);
+ fatalx("%s", err->msg);
+ }
+
+ iev = calloc(1, sizeof(*iev));
+ if (iev == NULL)
+ fatal("calloc");
+
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+
+ iev->handler = auth_accept;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, auth_accept, iev);
+ imsg_event_add(iev);
+
+ env->iev_auth = iev;
+}
+
+static void
+auth_launch(struct gotwebd *env)
+{
+#ifndef PROFILE
+ if (pledge("stdio unix", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_add(&env->iev_auth->ev, NULL);
+}
+
+static void
+auth_dispatch_main(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_CFG_SOCK:
+ get_auth_sock(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_START:
+ auth_launch(env);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+static void
+accept_paused(int fd, short event, void *arg)
+{
+ struct gotwebd *env = gotwebd_env;
+
+ event_add(&env->iev_auth->ev, NULL);
+}
+
+void
+gotwebd_auth(struct gotwebd *env, int fd)
+{
+ struct event sighup, sigint, sigusr1, sigchld, sigterm;
+ struct event_base *evb;
+
+ clients_init();
+ evb = event_init();
+
+ if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL)
+ fatal("malloc");
+ if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&env->iev_parent->ibuf);
+ env->iev_parent->handler = auth_dispatch_main;
+ env->iev_parent->data = env->iev_parent;
+ event_set(&env->iev_parent->ev, fd, EV_READ, auth_dispatch_main,
+ env->iev_parent);
+ event_add(&env->iev_parent->ev, NULL);
+ evtimer_set(&env->auth_pause_ev, accept_paused, NULL);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ signal_set(&sighup, SIGHUP, auth_sighdlr, env);
+ signal_add(&sighup, NULL);
+ signal_set(&sigint, SIGINT, auth_sighdlr, env);
+ signal_add(&sigint, NULL);
+ signal_set(&sigusr1, SIGUSR1, auth_sighdlr, env);
+ signal_add(&sigusr1, NULL);
+ signal_set(&sigchld, SIGCHLD, auth_sighdlr, env);
+ signal_add(&sigchld, NULL);
+ signal_set(&sigterm, SIGTERM, auth_sighdlr, env);
+ signal_add(&sigterm, NULL);
+
+#ifndef PROFILE
+ if (pledge("stdio recvfd unix", NULL) == -1)
+ fatal("pledge");
+#endif
+
+ event_dispatch();
+ event_base_free(evb);
+ auth_shutdown();
+}
blob - f66b9f38c71db3ea73f08f317e7446e2d3929e59
blob + 3d8bc92a0b02b0b2082667549e4fe43c6c1d7d8e
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
void gotwebd_configure_done(struct gotwebd *);
void gotwebd_sighdlr(int sig, short event, void *arg);
void gotwebd_shutdown(void);
+void gotwebd_dispatch_auth(int, short, void *);
void gotwebd_dispatch_server(int, short, void *);
void gotwebd_dispatch_gotweb(int, short, void *);
}
int
+main_compose_auth(struct gotwebd *env, uint32_t type, int fd,
+ const void *data, uint16_t len)
+{
+ return send_imsg(env->iev_auth, type, fd, data, len);
+}
+
+int
sockets_compose_main(struct gotwebd *env, uint32_t type, const void *d,
uint16_t len)
{
return (imsg_compose_event(env->iev_parent, type, 0, -1, -1, d, len));
+}
+
+void
+gotwebd_dispatch_auth(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
}
void
close(p[1]);
argv[argc++] = argv0;
- if (proc_type == GOTWEBD_PROC_SERVER) {
+ if (proc_type == GOTWEBD_PROC_AUTH) {
+ argv[argc++] = "-A";
+ argv[argc++] = username;
+ } else if (proc_type == GOTWEBD_PROC_SERVER) {
argv[argc++] = "-S";
argv[argc++] = username;
} else if (proc_type == GOTWEBD_PROC_GOTWEB) {
fatal("%s: calloc", __func__);
config_init(env);
- while ((ch = getopt(argc, argv, "D:dG:f:nS:vW:")) != -1) {
+ while ((ch = getopt(argc, argv, "A:D:dG:f:nS:vW:")) != -1) {
switch (ch) {
+ case 'A':
+ proc_type = GOTWEBD_PROC_AUTH;
+ gotwebd_username = optarg;
+ break;
case 'D':
if (cmdline_symset(optarg) < 0)
log_warnx("could not parse macro definition %s",
log_setverbose(env->gotwebd_verbose);
switch (proc_type) {
+ case GOTWEBD_PROC_AUTH:
+ setproctitle("auth");
+ log_procinit("auth");
+
+ if (setgroups(1, &pw->pw_gid) == -1 ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
+ fatal("failed to drop privileges");
+
+ gotwebd_auth(env, GOTWEBD_SOCK_FILENO);
+ return 1;
case GOTWEBD_PROC_SERVER:
setproctitle("server");
log_procinit("server");
evb = event_init();
+ env->iev_auth = calloc(1, sizeof(*env->iev_auth));
+ if (env->iev_auth == NULL)
+ fatal("calloc");
env->nserver = env->prefork_gotwebd;
env->iev_server = calloc(env->nserver, sizeof(*env->iev_server));
if (env->iev_server == NULL)
if (env->iev_gotweb == NULL)
fatal("calloc");
+ spawn_process(env, argv0, env->iev_auth, GOTWEBD_PROC_AUTH,
+ gotwebd_username, gotwebd_dispatch_auth);
+
for (i = 0; i < env->nserver; ++i) {
spawn_process(env, argv0, &env->iev_server[i],
GOTWEBD_PROC_SERVER, gotwebd_username,
fatalx("%s: send socket error", __func__);
}
+ if (auth_privinit(env, uid, gid) == -1)
+ fatalx("cannot open authentication socket");
+ if (main_compose_auth(env, GOTWEBD_IMSG_CFG_SOCK, env->auth_sock->fd,
+ NULL, 0) == -1)
+ fatal("main_compose_auth GOTWEBD_IMSG_CFG_SOCK");
+
/* send the temp files */
if (config_setfd(env) == -1)
fatalx("%s: send priv_fd error", __func__);
-1, NULL, 0) == -1)
fatal("main_compose_sockets GOTWEBD_IMSG_CTL_START");
}
+
+ if (env->servers_pending == 0 && env->gotweb_pending == 0) {
+ if (main_compose_auth(env, GOTWEBD_IMSG_CTL_START,
+ -1, NULL, 0) == -1)
+ fatal("main_compose_auth GOTWEBD_IMSG_CTL_START");
+ }
}
void
pid_t pid;
int i, status;
+ event_del(&env->iev_auth->ev);
+ imsgbuf_clear(&env->iev_auth->ibuf);
+ close(env->iev_auth->ibuf.fd);
+ env->iev_auth->ibuf.fd = -1;
+ free(env->iev_auth);
+
for (i = 0; i < env->nserver; ++i) {
event_del(&env->iev_server[i].ev);
imsgbuf_clear(&env->iev_server[i].ibuf);
blob - 562d13bf30399506f8f4f2c9eca0d103cf6e5cdd
blob + e26ec9ead0d150423a8c572c43c158099b606307
--- gotwebd/gotwebd.conf.5
+++ gotwebd/gotwebd.conf.5
.Sh GLOBAL CONFIGURATION
The available global configuration directives are as follows:
.Bl -tag -width Ds
+.It Ic authentication socket Ar path
+Set the
+.Ar path
+to the
+.Ux Ns -domain
+socket for user authentication requests from
+.Xr gotsh 1 .
+By default the path
+.Pa /var/run/gotweb-auth.sock
+will be used.
.It Ic chroot Ar path
Set the path to the
.Xr chroot 2
blob - 432a79667a3d6deab012c3bd82c9d857be510a0f
blob + 48619aa37f78c35dc4c873b7d3d8ea3c0ae218c8
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
enum gotwebd_proc_type {
GOTWEBD_PROC_PARENT,
+ GOTWEBD_PROC_AUTH,
GOTWEBD_PROC_SERVER,
GOTWEBD_PROC_GOTWEB,
};
GOTWEBD_IMSG_CFG_DONE,
GOTWEBD_IMSG_CTL_PIPE,
GOTWEBD_IMSG_CTL_START,
+ GOTWEBD_IMSG_AUTH_SOCK,
GOTWEBD_IMSG_REQ_PROCESS,
GOTWEBD_IMSG_REQ_DONE,
};
struct socketlist sockets;
struct addresslist addresses;
+ struct socket *auth_sock;
+ struct event auth_pause_ev;
+
int pack_fds[GOTWEB_PACK_NUM_TEMPFILES];
int priv_fd[PRIV_FDS__MAX];
int gotwebd_verbose;
struct imsgev *iev_parent;
+ struct imsgev *iev_auth;
struct imsgev *iev_server;
struct imsgev *iev_gotweb;
size_t nserver;
int sockets_compose_main(struct gotwebd *, uint32_t,
const void *, uint16_t);
int main_compose_gotweb(struct gotwebd *, uint32_t, int,
+ const void *, uint16_t);
+int main_compose_auth(struct gotwebd *, uint32_t, int,
const void *, uint16_t);
/* sockets.c */
void sockets(struct gotwebd *, int);
void sockets_parse_sockets(struct gotwebd *);
+struct socket *sockets_conf_new_socket(int, struct address *);
void sockets_socket_accept(int, short, void *);
int sockets_privinit(struct gotwebd *, struct socket *, uid_t, gid_t);
void sockets_purge(struct gotwebd *);
int config_getcfg(struct gotwebd *, struct imsg *);
int config_init(struct gotwebd *);
-/* ../lib/gotweb_auth.c */
-const struct got_error * gotweb_auth(int, int, int);
+/* auth.c */
+void gotwebd_auth(struct gotwebd *, int);
+int auth_privinit(struct gotwebd *env, uid_t, gid_t);
blob - 28cc307a5e9e04f189781f0f3c7c189a87700a17
blob + 016d8a449957831fcb0a45014636a91590ff80fc
--- gotwebd/parse.y
+++ gotwebd/parse.y
int n;
int get_addrs(const char *, const char *);
-int get_unix_addr(const char *);
+static struct address *get_unix_addr(const char *);
int addr_dup_check(struct addresslist *, struct address *);
void add_addr(struct address *);
%token MAX_REPOS_DISPLAY REPOS_PATH MAX_COMMITS_DISPLAY ON ERROR
%token SHOW_SITE_OWNER SHOW_REPO_CLONEURL PORT PREFORK RESPECT_EXPORTOK
%token SERVER CHROOT CUSTOM_CSS SOCKET
-%token SUMMARY_COMMITS_DISPLAY SUMMARY_TAGS_DISPLAY USER
+%token SUMMARY_COMMITS_DISPLAY SUMMARY_TAGS_DISPLAY USER AUTHENTICATION
%token <v.string> STRING
%token <v.number> NUMBER
free($3);
}
| LISTEN ON SOCKET STRING {
- if (get_unix_addr($4) == -1) {
+ struct address *h;
+ h = get_unix_addr($4);
+ if (h == NULL) {
yyerror("can't listen on %s", $4);
free($4);
YYERROR;
}
+ add_addr(h);
free($4);
}
| USER STRING {
yyerror("www user already specified");
free(gotwebd->www_user);
gotwebd->www_user = $3;
+ }
+ | AUTHENTICATION SOCKET STRING {
+ struct address *h;
+ h = get_unix_addr($3);
+ if (h == NULL) {
+ yyerror("can't listen on %s", $3);
+ free($3);
+ YYERROR;
+ }
+ if (gotwebd->auth_sock != NULL)
+ free(gotwebd->auth_sock);
+ gotwebd->auth_sock = sockets_conf_new_socket(-1, h);
+ free($3);
}
;
{
/* This has to be sorted always. */
static const struct keywords keywords[] = {
+ { "authentication", AUTHENTICATION },
{ "chroot", CHROOT },
{ "custom_css", CUSTOM_CSS },
{ "listen", LISTEN },
/* add the implicit listen on socket */
if (TAILQ_EMPTY(&gotwebd->addresses)) {
+ struct address *h;
char path[_POSIX_PATH_MAX];
if (strlcpy(path, gotwebd->httpd_chroot, sizeof(path))
yyerror("chroot path too long: %s",
gotwebd->httpd_chroot);
}
- if (get_unix_addr(path) == -1)
+ h = get_unix_addr(path);
+ if (h == NULL)
yyerror("can't listen on %s", path);
+ add_addr(h);
}
if (errors)
/* setup our listening sockets */
sockets_parse_sockets(env);
+
+ /* Add implicit auth socket */
+ if (gotwebd->auth_sock == NULL) {
+ struct address *h;
+ h = get_unix_addr(GOTWEBD_AUTH_SOCKET);
+ if (h == NULL) {
+ fprintf(stderr, "cannot listen on %s",
+ GOTWEBD_AUTH_SOCKET);
+ return (-1);
+ }
+ gotwebd->auth_sock = sockets_conf_new_socket(-1, h);
+ }
return (0);
}
return (0);
}
-int
+static struct address *
get_unix_addr(const char *path)
{
struct address *h;
if (strlcpy(sun->sun_path, path, sizeof(sun->sun_path)) >=
sizeof(sun->sun_path)) {
log_warnx("socket path too long: %s", sun->sun_path);
- return (-1);
+ return NULL;
}
- add_addr(h);
- return (0);
+ return h;
}
int
blob - 78ec58685de17ce8a866d30f36a5597b2d6f85da
blob + 66d8e76df0aa38dd5b4c508d577b4b6fa7039ba4
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
static int sockets_accept_reserve(int, struct sockaddr *, socklen_t *,
int, volatile int *);
-static struct socket *sockets_conf_new_socket(struct gotwebd *,
- int, struct address *);
-
int cgi_inflight = 0;
/* Request hash table needs some spare room to avoid collisions. */
int sock_id = 1;
TAILQ_FOREACH(a, &env->addresses, entry) {
- new_sock = sockets_conf_new_socket(env, sock_id, a);
+ new_sock = sockets_conf_new_socket(sock_id, a);
if (new_sock) {
sock_id++;
TAILQ_INSERT_TAIL(&env->sockets,
}
}
-static struct socket *
-sockets_conf_new_socket(struct gotwebd *env, int id, struct address *a)
+struct socket *
+sockets_conf_new_socket(int id, struct address *a)
{
struct socket *sock;
struct address *acp;