commit ff2b55acc0b4c0c704bfbafbb9ff1a74be3f49af from: Stefan Sperling date: Thu Apr 17 16:19:58 2025 UTC add an auth process to gotwebd (WIP: it receives requests, but does nothing) commit - e39d79e3c6d16ad1f982e9c9a8c2f99d368bd15c commit + ff2b55acc0b4c0c704bfbafbb9ff1a74be3f49af blob - 545a13d2e5aba6dc9df486f7300af0acf23c4df7 blob + 0505fbd1f8d0b37fded75218be702fa5b8fe4fab --- gotwebd/Makefile +++ gotwebd/Makefile @@ -5,7 +5,7 @@ .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 @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2025 Stefan Sperling + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 @@ -52,6 +52,7 @@ int gotwebd_configure(struct gotwebd *, uid_t, gid_t) 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 *); @@ -148,10 +149,63 @@ main_compose_gotweb(struct gotwebd *env, uint32_t type } 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 @@ -312,7 +366,10 @@ spawn_process(struct gotwebd *env, const char *argv0, 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) { @@ -377,8 +434,12 @@ main(int argc, char **argv) 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", @@ -449,6 +510,17 @@ main(int argc, char **argv) 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"); @@ -485,6 +557,9 @@ main(int argc, char **argv) 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) @@ -493,6 +568,9 @@ main(int argc, char **argv) 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, @@ -603,6 +681,12 @@ gotwebd_configure(struct gotwebd *env, uid_t uid, gid_ 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__); @@ -634,6 +718,12 @@ gotwebd_configure_done(struct gotwebd *env) -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 @@ -643,6 +733,12 @@ gotwebd_shutdown(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 @@ -47,6 +47,16 @@ listen on $lan_addr port 9090 .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 @@ -127,6 +127,7 @@ struct got_reflist_head; enum gotwebd_proc_type { GOTWEBD_PROC_PARENT, + GOTWEBD_PROC_AUTH, GOTWEBD_PROC_SERVER, GOTWEBD_PROC_GOTWEB, }; @@ -138,6 +139,7 @@ enum imsg_type { GOTWEBD_IMSG_CFG_DONE, GOTWEBD_IMSG_CTL_PIPE, GOTWEBD_IMSG_CTL_START, + GOTWEBD_IMSG_AUTH_SOCK, GOTWEBD_IMSG_REQ_PROCESS, GOTWEBD_IMSG_REQ_DONE, }; @@ -361,6 +363,9 @@ struct gotwebd { 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]; @@ -372,6 +377,7 @@ struct gotwebd { int gotwebd_verbose; struct imsgev *iev_parent; + struct imsgev *iev_auth; struct imsgev *iev_server; struct imsgev *iev_gotweb; size_t nserver; @@ -460,11 +466,14 @@ int main_compose_sockets(struct gotwebd *, uint32_t, 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 *); @@ -543,5 +552,6 @@ int config_getfd(struct gotwebd *, struct imsg *); 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 @@ -96,7 +96,7 @@ int getservice(const char *); 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 *); @@ -115,7 +115,7 @@ typedef struct { %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 STRING %token NUMBER @@ -234,11 +234,14 @@ main : PREFORK 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 { @@ -252,6 +255,19 @@ main : PREFORK NUMBER { 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); } ; @@ -454,6 +470,7 @@ lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { + { "authentication", AUTHENTICATION }, { "chroot", CHROOT }, { "custom_css", CUSTOM_CSS }, { "listen", LISTEN }, @@ -845,6 +862,7 @@ parse_config(const char *filename, struct gotwebd *env /* 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)) @@ -857,8 +875,10 @@ parse_config(const char *filename, struct gotwebd *env 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) @@ -866,6 +886,18 @@ parse_config(const char *filename, struct gotwebd *env /* 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); } @@ -1068,7 +1100,7 @@ get_addrs(const char *hostname, const char *servname) return (0); } -int +static struct address * get_unix_addr(const char *path) { struct address *h; @@ -1087,11 +1119,10 @@ get_unix_addr(const char *path) 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 @@ -74,9 +74,6 @@ static int sockets_create_socket(struct address *); 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. */ @@ -213,7 +210,7 @@ sockets_parse_sockets(struct gotwebd *env) 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, @@ -222,8 +219,8 @@ sockets_parse_sockets(struct gotwebd *env) } } -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;