commit - e240092c03160c453e59bea3aff1b6ec606b1539
commit + 9e6d4144ce019af2f5268ad4c9554f3a005c53dc
blob - 29487341845ed5d0e00ec472e2593c862e4503d1
blob + 4021e113af0bec3a58a00ea8dc9e1e77f377c553
--- gotwebd/access.c
+++ gotwebd/access.c
#include <event.h>
#include <imsg.h>
#include <pwd.h>
+#include <signal.h>
#include <grp.h>
#include <stdlib.h>
#include <unistd.h>
#include "gotwebd.h"
#include "log.h"
+static char auth_token_secret[32];
+
+static void
+access_shutdown(void)
+{
+ struct gotwebd *env = gotwebd_env;
+ int i;
+
+ imsgbuf_clear(&env->iev_parent->ibuf);
+
+ for (i = 0; i < env->nserver; i++)
+ imsgbuf_clear(&env->iev_login[i].ibuf);
+
+ free(env->iev_parent);
+ free(env->iev_login);
+ free(env);
+
+ exit(0);
+}
+
+static void
+access_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:
+ access_shutdown();
+ break;
+ default:
+ log_warn("unexpected signal %d", sig);
+ break;
+ }
+}
+
#if 0
static int
parseuid(const char *s, uid_t *uid)
return access;
#endif
}
+
+static void
+access_launch(struct gotwebd *env)
+{
+ int i;
+
+ for (i = 0; i < env->nserver; i++)
+ event_add(&env->iev_login[i].ev, NULL);
+}
+
+static void
+access_dispatch_login(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);
+ }
+}
+
+static void
+recv_login_pipe(struct gotwebd *env, struct imsg *imsg)
+{
+ struct imsgev *iev;
+ int fd;
+
+ if (env->server_cnt >= env->nserver)
+ fatalx("too many login pipes received");
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1)
+ fatalx("invalid login pipe fd");
+
+ iev = &env->iev_login[env->server_cnt];
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+
+ iev->handler = access_dispatch_login;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, access_dispatch_login, iev);
+ imsg_event_add(iev);
+
+ env->server_cnt++;
+}
+
+static void
+access_dispatch_main(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ struct server *srv;
+ struct gotwebd_repo *repo;
+ 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_ACCESS_RULE:
+ if (TAILQ_EMPTY(&env->servers)) {
+ /* global access rule */
+ config_get_access_rule(&env->access_rules,
+ &imsg);
+ } else {
+ srv = TAILQ_LAST(&env->servers, serverlist);
+ if (TAILQ_EMPTY(&srv->repos)) {
+ /* per-server access rule */
+ config_get_access_rule(
+ &srv->access_rules, &imsg);
+ } else {
+ /* per-repository access rule */
+ repo = TAILQ_LAST(&srv->repos,
+ gotwebd_repolist);
+ config_get_access_rule(
+ &repo->access_rules, &imsg);
+ }
+ }
+ break;
+ case GOTWEBD_IMSG_CFG_SRV:
+ config_getserver(gotwebd_env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CFG_REPO:
+ if (TAILQ_EMPTY(&env->servers))
+ fatalx("%s: unexpected CFG_REPO msg", __func__);
+ srv = TAILQ_LAST(&env->servers, serverlist);
+ config_get_repository(&srv->repos, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_PIPE:
+ recv_login_pipe(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_START:
+ access_launch(env);
+ break;
+ case GOTWEBD_IMSG_AUTH_SECRET:
+ if (imsg_get_data(&imsg, auth_token_secret,
+ sizeof(auth_token_secret)) == -1)
+ fatalx("%s: invalid AUTH_SECRET msg", __func__);
+ break;
+ case GOTWEBD_IMSG_AUTH_CONF:
+ if (imsg_get_data(&imsg, &env->auth_config,
+ sizeof(env->auth_config)) == -1)
+ fatalx("%s: invalid AUTH_CONF msg", __func__);
+ break;
+ case GOTWEBD_IMSG_WWW_UID:
+ if (imsg_get_data(&imsg, &env->www_uid,
+ sizeof(env->www_uid)) == -1)
+ fatalx("%s: invalid WWW_UID msg", __func__);
+ 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);
+ }
+}
+
+void
+gotwebd_access(struct gotwebd *env, int fd)
+{
+ struct event sighup, sigint, sigusr1, sigchld, sigterm;
+ struct event_base *evb;
+
+ 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 = access_dispatch_main;
+ env->iev_parent->data = env->iev_parent;
+ event_set(&env->iev_parent->ev, fd, EV_READ, access_dispatch_main,
+ env->iev_parent);
+ event_add(&env->iev_parent->ev, NULL);
+
+ env->nserver = env->prefork_gotwebd;
+ env->iev_login = calloc(env->nserver, sizeof(*env->iev_login));
+ if (env->iev_login == NULL)
+ fatal("calloc");
+
+ signal(SIGPIPE, SIG_IGN);
+
+ signal_set(&sighup, SIGHUP, access_sighdlr, env);
+ signal_add(&sighup, NULL);
+ signal_set(&sigint, SIGINT, access_sighdlr, env);
+ signal_add(&sigint, NULL);
+ signal_set(&sigusr1, SIGUSR1, access_sighdlr, env);
+ signal_add(&sigusr1, NULL);
+ signal_set(&sigchld, SIGCHLD, access_sighdlr, env);
+ signal_add(&sigchld, NULL);
+ signal_set(&sigterm, SIGTERM, access_sighdlr, env);
+ signal_add(&sigterm, NULL);
+
+#ifndef PROFILE
+ if (pledge("stdio getpw recvfd", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_dispatch();
+ event_base_free(evb);
+ access_shutdown();
+}
blob - a2bcb51ecdc5ad72372dc40a7d33332c84a54576
blob + 1145399328b3be0c33705a4e62c64acf5072b386
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
void gotwebd_sighdlr(int sig, short event, void *arg);
void gotwebd_shutdown(void);
void gotwebd_dispatch_auth(int, short, void *);
+void gotwebd_dispatch_access(int, short, void *);
void gotwebd_dispatch_server(int, short, void *);
void gotwebd_dispatch_login(int, short, void *);
void gotwebd_dispatch_gotweb(int, short, void *);
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
+gotwebd_dispatch_access(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
struct imsgbuf *ibuf;
} else if (proc_type == GOTWEBD_PROC_LOGIN) {
argv[argc++] = "-L";
argv[argc++] = username;
+ } else if (proc_type == GOTWEBD_PROC_ACCESS) {
+ argv[argc++] = "-C";
+ argv[argc++] = username;
} else if (proc_type == GOTWEBD_PROC_GOTWEB) {
argv[argc++] = "-G";
argv[argc++] = username;
fatal("%s: calloc", __func__);
config_init(env);
- while ((ch = getopt(argc, argv, "A:D:dG:f:L:nS:vW:")) != -1) {
+ while ((ch = getopt(argc, argv, "A:C:D:dG:f:L:nS:vW:")) != -1) {
switch (ch) {
case 'A':
proc_type = GOTWEBD_PROC_AUTH;
gotwebd_username = optarg;
break;
+ case 'C':
+ proc_type = GOTWEBD_PROC_ACCESS;
+ gotwebd_username = optarg;
+ break;
case 'D':
if (cmdline_symset(optarg) < 0)
log_warnx("could not parse macro definition %s",
gotwebd_login(env, GOTWEBD_SOCK_FILENO);
return 1;
+ case GOTWEBD_PROC_ACCESS:
+ setproctitle("access");
+ log_procinit("access");
+
+ 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_access(env, GOTWEBD_SOCK_FILENO);
+ return 1;
case GOTWEBD_PROC_GOTWEB:
setproctitle("gotweb");
log_procinit("gotweb");
env->iev_auth = calloc(1, sizeof(*env->iev_auth));
if (env->iev_auth == NULL)
fatal("calloc");
+ env->iev_access = calloc(1, sizeof(*env->iev_access));
+ if (env->iev_access == NULL)
+ fatal("calloc");
env->nserver = env->prefork_gotwebd;
env->iev_server = calloc(env->nserver, sizeof(*env->iev_server));
if (env->iev_server == NULL)
spawn_process(env, argv0, env->iev_auth, GOTWEBD_PROC_AUTH,
gotwebd_username, gotwebd_dispatch_auth);
+ spawn_process(env, argv0, env->iev_access, GOTWEBD_PROC_ACCESS,
+ gotwebd_username, gotwebd_dispatch_access);
for (i = 0; i < env->nserver; ++i) {
spawn_process(env, argv0, &env->iev_server[i],
arc4random_buf(auth_token_secret, sizeof(auth_token_secret));
/* send our global access rules */
+ config_set_access_rules(env->iev_access, &env->access_rules);
for (i = 0; i < env->nserver; ++i) {
config_set_access_rules(&env->iev_login[i],
&env->access_rules);
if (main_compose_gotweb(env, GOTWEBD_IMSG_CFG_SRV,
-1, srv, sizeof(*srv)) == -1)
fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SRV");
+ if (send_imsg(env->iev_access, GOTWEBD_IMSG_CFG_SRV,
+ -1, srv, sizeof(*srv)) == -1)
+ fatal("send_imsg GOTWEBD_IMSG_CFG_SRV");
/* send per-server access rules */
+ config_set_access_rules(env->iev_access, &srv->access_rules);
for (i = 0; i < env->nserver; ++i) {
config_set_access_rules(&env->iev_login[i],
&srv->access_rules);
&srv->access_rules);
}
- /* send repositories */
+ /* send repositories and per-repository access rules */
TAILQ_FOREACH(repo, &srv->repos, entry) {
+ config_set_repository(env->iev_access, repo);
+ config_set_access_rules(env->iev_access,
+ &repo->access_rules);
+
for (i = 0; i < env->nserver; i++) {
config_set_repository(&env->iev_login[i],
repo);
config_set_repository(&env->iev_gotweb[i],
repo);
- /* send per-repository access rules */
config_set_access_rules(&env->iev_login[i],
&repo->access_rules);
config_set_access_rules(&env->iev_gotweb[i],
}
}
+ if (imsgbuf_flush(&env->iev_access->ibuf) == -1)
+ fatal("imsgbuf_flush");
+ imsg_event_add(env->iev_access);
+
for (i = 0; i < env->nserver; i++) {
if (imsgbuf_flush(&env->iev_login[i].ibuf) == -1)
fatal("imsgbuf_flush");
if (main_compose_gotweb(env, GOTWEBD_IMSG_AUTH_CONF, -1,
&env->auth_config, sizeof(env->auth_config)) == -1)
fatal("main_compose_login GOTWEB_IMSG_AUTH_CONF");
+ if (send_imsg(env->iev_access, GOTWEBD_IMSG_AUTH_CONF, -1,
+ &env->auth_config, sizeof(env->auth_config)) == -1)
+ fatal("send_imsg GOTWEB_IMSG_AUTH_CONF");
if (main_compose_login(env, GOTWEBD_IMSG_WWW_UID, -1,
&env->www_uid, sizeof(env->www_uid)) == -1)
if (main_compose_gotweb(env, GOTWEBD_IMSG_WWW_UID, -1,
&env->www_uid, sizeof(env->www_uid)) == -1)
fatal("main_compose_login GOTWEB_IMSG_WWW_UID");
+ if (send_imsg(env->iev_access, GOTWEBD_IMSG_WWW_UID, -1,
+ &env->www_uid, sizeof(env->www_uid)) == -1)
+ fatal("send_imsg GOTWEB_IMSG_WWW_UID");
if (main_compose_login(env, GOTWEBD_IMSG_AUTH_SECRET, -1,
auth_token_secret, sizeof(auth_token_secret)) == -1)
if (main_compose_auth(env, GOTWEBD_IMSG_AUTH_SECRET, -1,
auth_token_secret, sizeof(auth_token_secret)) == -1)
fatal("main_compose_gotweb GOTWEB_IMSG_AUTH_SECRET");
+ if (send_imsg(env->iev_access, GOTWEBD_IMSG_AUTH_SECRET, -1,
+ auth_token_secret, sizeof(auth_token_secret)) == -1)
+ fatal("send_imsg GOTWEB_IMSG_AUTH_SECRET");
explicit_bzero(auth_token_secret, sizeof(auth_token_secret));
env->iev_auth->ibuf.fd = -1;
free(env->iev_auth);
+ event_del(&env->iev_access->ev);
+ imsgbuf_clear(&env->iev_access->ibuf);
+ close(env->iev_access->ibuf.fd);
+ env->iev_access->ibuf.fd = -1;
+ free(env->iev_access);
+
for (i = 0; i < env->nserver; ++i) {
event_del(&env->iev_server[i].ev);
imsgbuf_clear(&env->iev_server[i].ibuf);
blob - cc02ed610da95de3915587d1b15df67214fff46e
blob + e3a745e3df95c9878c6d2fe4843e85f4d2aaafbe
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
struct got_reflist_head;
enum gotwebd_proc_type {
- GOTWEBD_PROC_PARENT,
- GOTWEBD_PROC_AUTH,
- GOTWEBD_PROC_SERVER,
- GOTWEBD_PROC_LOGIN,
- GOTWEBD_PROC_GOTWEB,
+ GOTWEBD_PROC_PARENT, /* read configuration and start processes */
+ GOTWEBD_PROC_AUTH, /* authenticate user via sshd + getpeereid(3) */
+ GOTWEBD_PROC_SERVER, /* FastCGI server on unix-socket or TCP */
+ GOTWEBD_PROC_LOGIN, /* drop unauthenticated/unauthorized requests */
+ GOTWEBD_PROC_ACCESS, /* handle auth secrets and access permissions */
+ GOTWEBD_PROC_GOTWEB, /* read repositories and render HTML */
};
enum imsg_type {
struct imsgev *iev_parent;
struct imsgev *iev_auth;
+ struct imsgev *iev_access;
struct imsgev *iev_server;
struct imsgev *iev_login;
struct imsgev *iev_gotweb;
/* access.c */
enum gotwebd_access access_check(uid_t, struct gotwebd_access_rule_list *);
+void gotwebd_access(struct gotwebd *, int);