refactor(*): drop env overrides, and add man pages
16 files changed, -60/+391
hedge/Makefile
@@ -23,8 +23,12 @@ install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f hedge ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/hedge+ mkdir -p ${DESTDIR}${MANPREFIX}/man1+ cp -f hedge.1 ${DESTDIR}${MANPREFIX}/man1+ chmod 644 ${DESTDIR}${MANPREFIX}/man1/hedge.1 uninstall:- rm -f ${DESTDIR}${PREFIX}/bin/hedge+ rm -f ${DESTDIR}${PREFIX}/bin/hedge\+ ${DESTDIR}${MANPREFIX}/man1/hedge.1 .PHONY: all clean install uninstall
hedge/config.mk
@@ -1,4 +1,5 @@-PREFIX = /usr/local+PREFIX = /usr/local+MANPREFIX = ${PREFIX}/share/man CPPFLAGS = -D_XOPEN_SOURCE=700 CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS}
hedge/hedge.1
@@ -0,0 +1,89 @@+.TH HEDGE 1 hedge+.SH NAME+hedge \- git access control for ssh+.SH SYNOPSIS+.B hedge+.I id+.SH DESCRIPTION+.B hedge+is run as the forced command of an ssh key and lets the identity+.I id+fetch from or push to the repositories the+.B acl+file grants it.+It reads the git command from+.BR SSH_ORIGINAL_COMMAND ,+checks it and hands it to+.B gitshell+as+.IR verb " '" root / repo .git'.+Any other command, including an interactive login, is refused.+.P+.B git-upload-pack+and+.B git-upload-archive+need read access,+.B git-receive-pack+needs write access.+Write access implies read access.+.P+The repository path may be quoted, may start with a slash and may end+with a slash or+.BR .git .+What remains must consist of+.BR / -separated+segments matching+.BR ^[A-Za-z0-9_][A-Za-z0-9._-]*$ ,+so nested repositories such as+.B group/repo+are allowed.+.SH FILES+.TP+.B acl+One grant per line:+.IP+.nf+.IR repo " " read | write " " id+.fi+.IP+Fields are separated by a single space and+.I repo+is written without+.BR .git .+There are no comments or wildcards.+.TP+.IR root / repo .git+The bare repositories.+.SH EXIT STATUS+.TP+.B 1+Access was denied or+.B gitshell+could not be run.+.P+Otherwise the exit status is that of+.BR git-shell .+.SH EXAMPLES+.B acl:+.P+.nf+greenhouse write lostduk+greenhouse read alice+.fi+.P+.BR authorized_keys :+.P+.nf+command="/usr/local/bin/hedge lostduk",restrict ssh-ed25519 AAAA...+.fi+.P+Clone with+.IR "git clone git@host:greenhouse" .+.SH CUSTOMIZATION+.B hedge+is configured by editing+.I config.h+and recompiling.+.SH SEE ALSO+.BR git-shell (1),+.BR sshd (8)
hedge/hedge.c
@@ -108,7 +108,7 @@ trim(char *path) void usage(void) {- fputs("usage: hedge [-a acl] [-r root] id\n", stderr);+ fputs("usage: hedge id\n", stderr); exit(1); } @@ -145,23 +145,10 @@ main(int argc, char *argv[]) const char *s; char *path; size_t i;- int c;-- while ((c = getopt(argc, argv, "a:r:")) != -1) {- switch (c) {- case 'a':- acl = optarg;- break;- case 'r':- root = optarg;- break;- default:- usage();- }- }- if (argc - optind != 1)++ if (argc != 2) usage();- id = argv[optind];+ id = argv[1]; if (!(s = getenv("SSH_ORIGINAL_COMMAND"))) s = "";
herbarium/Makefile
@@ -27,10 +27,14 @@ install: all cp -f style.css icon.svg ${DESTDIR}${PREFIX}/share/herbarium chmod 644 ${DESTDIR}${PREFIX}/share/herbarium/style.css\ ${DESTDIR}${PREFIX}/share/herbarium/icon.svg+ mkdir -p ${DESTDIR}${MANPREFIX}/man1+ cp -f herbarium.1 ${DESTDIR}${MANPREFIX}/man1+ chmod 644 ${DESTDIR}${MANPREFIX}/man1/herbarium.1 uninstall: rm -f ${DESTDIR}${PREFIX}/bin/herbarium\ ${DESTDIR}${PREFIX}/share/herbarium/style.css\- ${DESTDIR}${PREFIX}/share/herbarium/icon.svg+ ${DESTDIR}${PREFIX}/share/herbarium/icon.svg\+ ${DESTDIR}${MANPREFIX}/man1/herbarium.1 .PHONY: all clean install uninstall
herbarium/config.def.h
@@ -9,7 +9,6 @@ static const int maxmsgs = 20000; static const int maxhdr = 64 * 1024; static const int maxbody = 512 * 1024; static const int maxdepth = 8;-static const int maxcpu = 10; static const Service services[] = { { "git", "https://git.lostduk.com/" },
herbarium/config.mk
@@ -1,4 +1,5 @@-PREFIX = /usr/local+PREFIX = /usr/local+MANPREFIX = ${PREFIX}/share/man CPPFLAGS = -D_XOPEN_SOURCE=700 CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS}
herbarium/herbarium.1
@@ -0,0 +1,135 @@+.TH HERBARIUM 1 herbarium+.SH NAME+herbarium \- mailing list archive web interface+.SH SYNOPSIS+.B herbarium+.SH DESCRIPTION+.B herbarium+is a CGI program that shows the archives+.BR pollen (1)+keeps in+.IR root / list /archive.+Only lists whose name matches+.B ^[a-z0-9][a-z0-9-]*$+and that contain a+.B public+file are shown.+.P+Each request reads the headers of the newest+.B maxmsgs+messages, by file modification time, from the+.B new+and+.B cur+directories of the archive.+Messages are threaded by+.B In-Reply-To+and then+.BR References .+If several messages share a+.BR Message-ID ,+the oldest one is kept.+A missing or implausible+.B Date+is replaced by the file modification time.+.P+Pages are selected by+.BR PATH_INFO ,+where+.I id+is a+.B Message-ID+without angle brackets:+.TP+.B /+Index of all public lists with description, address, number of threads+and age of the last message.+.TP+.IB /list /+Threads, most recently active first,+.B perpage+per page; older pages are reached with+.BI ?ofs= n .+.TP+.IB /list / id /+The thread started by+.IR id .+Any other message redirects to its thread.+Plain text and patch parts are shown, decoded to UTF-8, up to+.B maxbody+bytes per message; HTML parts and attachments are only named.+Multipart nesting is followed up to+.B maxdepth+levels.+.TP+.IB /list / id /raw+The message as archived, served as+.BR text/plain .+.TP+.IB /list / id /t.mbox+The whole thread as an mboxrd file.+.P+Every response carries a Content-Security-Policy that allows only the+stylesheet and icon from the same origin.+.SH ENVIRONMENT+.TP+.B PATH_INFO+The page.+.TP+.B SCRIPT_NAME+URL prefix for links.+.TP+.B QUERY_STRING+.BI ofs= n+for the thread list.+.SH FILES+.TP+.IR root / list /public+Present if the archive is public.+.TP+.IR root / list /description+One line describing the list.+.TP+.IR root / list /archive/+Maildir written by+.BR pollen (1).+.B herbarium+only needs read access, for example through pollen's group.+.TP+.IR PREFIX /share/herbarium/style.css ", " icon.svg+Stylesheet and icon, to be served at+.B css+and+.BR icon .+.SH EXAMPLES+.B herbarium+sets no resource limits itself.+Run it through a wrapper:+.P+.nf+#!/bin/sh+ulimit -t 10+exec /usr/local/bin/herbarium+.fi+.P+.BR nginx :+.P+.nf+location = /style.css { alias /usr/local/share/herbarium/style.css; }+location = /icon.svg { alias /usr/local/share/herbarium/icon.svg; }+location / {+ include fastcgi_params;+ fastcgi_param SCRIPT_FILENAME /usr/local/bin/herbarium-cgi;+ fastcgi_param SCRIPT_NAME "";+ fastcgi_param PATH_INFO $uri;+ fastcgi_pass unix:/run/fcgiwrap.sock;+}+.fi+.SH CUSTOMIZATION+.B herbarium+is configured by editing+.I config.h+and recompiling.+.SH SEE ALSO+.BR pollen (1),+.BR petal (1)
herbarium/herbarium.c
@@ -12,7 +12,6 @@ #include <strings.h> #include <time.h> #include <unistd.h>-#include <sys/resource.h> #include <sys/stat.h> /* macros */@@ -1850,7 +1849,6 @@ tou8(const char *cs, const char *s, size_t n, Buf *out) char name[64], tmp[1024], *in, *o; size_t i, il, ol, r; iconv_t cd;- unsigned char c; for (i = 0; cs[i] && cs[i] != '*'; i++) { if (i + 1 >= sizeof(name) || !(isalnum((unsigned char)cs[i])@@ -1864,18 +1862,6 @@ tou8(const char *cs, const char *s, size_t n, Buf *out) bufadd(out, s, n); return 0; }- if (!strcasecmp(name, "iso-8859-1") || !strcasecmp(name, "latin1")) {- for (i = 0; i < n; i++) {- c = (unsigned char)s[i];- if (c < 0x80) {- bufc(out, c);- } else {- bufc(out, 0xc0 | c >> 6);- bufc(out, 0x80 | (c & 0x3f));- }- }- return 0;- } if ((cd = iconv_open("UTF-8", name)) == (iconv_t)-1) return -1; in = (char *)s;@@ -1979,15 +1965,7 @@ main(void) { char path[2048]; const char *q;- struct rlimit rl;-- rl.rlim_cur = rl.rlim_max = maxcpu;- setrlimit(RLIMIT_CPU, &rl);- root = envor("HERBARIUM_ROOT", root);- domain = envor("HERBARIUM_DOMAIN", domain);- css = envor("HERBARIUM_CSS", css);- icon = envor("HERBARIUM_ICON", icon);- title = envor("HERBARIUM_TITLE", title);+ base = envor("SCRIPT_NAME", ""); q = envor("QUERY_STRING", ""); if (!strncmp(q, "ofs=", 4) && (ofs = strtol(q + 4, NULL, 10)) < 0)
petal/Makefile
@@ -27,10 +27,14 @@ install: all cp -f style.css icon.svg ${DESTDIR}${PREFIX}/share/petal chmod 644 ${DESTDIR}${PREFIX}/share/petal/style.css\ ${DESTDIR}${PREFIX}/share/petal/icon.svg+ mkdir -p ${DESTDIR}${MANPREFIX}/man1+ cp -f petal.1 ${DESTDIR}${MANPREFIX}/man1+ chmod 644 ${DESTDIR}${MANPREFIX}/man1/petal.1 uninstall: rm -f ${DESTDIR}${PREFIX}/bin/petal\ ${DESTDIR}${PREFIX}/share/petal/style.css\- ${DESTDIR}${PREFIX}/share/petal/icon.svg+ ${DESTDIR}${PREFIX}/share/petal/icon.svg\+ ${DESTDIR}${MANPREFIX}/man1/petal.1 .PHONY: all clean install uninstall
petal/config.def.h
@@ -9,7 +9,6 @@ static const int maxdepth = 8; static const int barwidth = 40; static const int maxblob = 512 * 1024; static const int maxdiff = 10000;-static const int maxcpu = 10; static const Service services[] = { { "git", "https://git.lostduk.com/" },
petal/config.mk
@@ -1,4 +1,5 @@-PREFIX = /usr/local+PREFIX = /usr/local+MANPREFIX = ${PREFIX}/share/man GIT2INC = /usr/local/include GIT2LIB = /usr/local/lib
petal/petal.1
@@ -0,0 +1,136 @@+.TH PETAL 1 petal+.SH NAME+petal \- git web interface+.SH SYNOPSIS+.B petal+.SH DESCRIPTION+.B petal+is a CGI program that shows the bare git repositories in+.IR root .+A directory+.IR root / name .git+is a repository named+.IR name ;+names may be nested, such as+.BR group/repo ,+up to+.B maxdepth+levels.+Only repositories containing+.B git-daemon-export-ok+are shown.+.P+Pages are selected by+.BR PATH_INFO .+The longest prefix that names a repository is the repository, the rest+is the page.+A+.I ref+is a branch, a tag or a commit id of 4 to 40 hex digits; the longest+prefix of the rest that resolves to one is taken.+Without a+.IR ref ,+.B HEAD+is used.+.TP+.B /+Index of all repositories with description, owner and age of the last+commit.+.TP+.IR /repo ", " /repo /log[/ ref ]+Log,+.B loglimit+commits per page; older pages are reached with+.BI ?ofs= n .+.TP+.IR /repo /tree[/ ref [/ path ]]+Directory listing or file view with line anchors.+Files larger than+.B maxblob+bytes are not shown.+.TP+.IR /repo /raw/ ref / path+The file as is, served as+.B text/plain+or, if binary,+.BR application/octet-stream .+.TP+.IR /repo /commit/ id+Commit metadata, diffstat and diff, cut after+.B maxdiff+lines.+.I id+must be a commit id of 4 to 40 hex digits.+.TP+.IR /repo /refs+Branches and tags.+.P+Every response carries a Content-Security-Policy that allows only the+stylesheet and icon from the same origin.+.SH ENVIRONMENT+.TP+.B PATH_INFO+The page.+.TP+.B SCRIPT_NAME+URL prefix for links.+.TP+.B QUERY_STRING+.BI ofs= n+for the log.+.TP+.B HOME+libgit2 refuses repositories owned by another user unless they are+listed as+.B safe.directory+in+.IR $HOME /.gitconfig.+.SH FILES+.TP+.IR root / repo .git/description+One line describing the repository.+.TP+.IR root / repo .git/owner+One line naming the owner.+.TP+.IR root / repo .git/git-daemon-export-ok+Present if the repository is public.+.TP+.IR PREFIX /share/petal/style.css ", " icon.svg+Stylesheet and icon, to be served at+.B css+and+.BR icon .+.SH EXAMPLES+.B petal+sets no resource limits itself.+Run it through a wrapper:+.P+.nf+#!/bin/sh+ulimit -t 10+exec /usr/local/bin/petal+.fi+.P+.BR nginx :+.P+.nf+location = /style.css { alias /usr/local/share/petal/style.css; }+location = /icon.svg { alias /usr/local/share/petal/icon.svg; }+location / {+ include fastcgi_params;+ fastcgi_param SCRIPT_FILENAME /usr/local/bin/petal-cgi;+ fastcgi_param SCRIPT_NAME "";+ fastcgi_param PATH_INFO $uri;+ fastcgi_pass unix:/run/fcgiwrap.sock;+}+.fi+.SH CUSTOMIZATION+.B petal+is configured by editing+.I config.h+and recompiling.+.SH SEE ALSO+.BR herbarium (1),+.BR hedge (1),+.BR git-http-backend (1)
petal/petal.c
@@ -7,7 +7,6 @@ #include <stdlib.h> #include <string.h> #include <time.h>-#include <sys/resource.h> #include <sys/stat.h> #include <git2.h> @@ -1150,15 +1149,7 @@ main(void) { char path[1024]; const char *q;- struct rlimit rl;-- rl.rlim_cur = rl.rlim_max = maxcpu;- setrlimit(RLIMIT_CPU, &rl);- root = envor("PETAL_ROOT", root);- css = envor("PETAL_CSS", css);- icon = envor("PETAL_ICON", icon);- clone = envor("PETAL_CLONE", clone);- title = envor("PETAL_TITLE", title);+ base = envor("SCRIPT_NAME", ""); q = envor("QUERY_STRING", ""); if (!strncmp(q, "ofs=", 4) && (ofs = strtol(q + 4, NULL, 10)) < 0)
pollen/pollen.1
@@ -192,5 +192,6 @@ is configured by editing .I config.h and recompiling. .SH SEE ALSO+.BR herbarium (1), .BR pipe (8), .BR sendmail (1)
pollen/pollen.c
@@ -305,7 +305,8 @@ int dropped(size_t pos) { return (hdrlen - pos >= 5 && !strncasecmp(msg + pos, "List-", 5))- || isfield(pos, "Return-Path") || isfield(pos, "Delivered-To");+ || isfield(pos, "Return-Path") || isfield(pos, "Delivered-To")+ || isfield(pos, "Precedence"); } size_t@@ -876,6 +877,7 @@ setsub(const char *addr, int add) } while (in && getline(&line, &cap, in) > 0) { line[strcspn(line, "\r\n")] = '\0';+ lower(line); if (!*line) continue; if (!strcmp(line, addr)) {@@ -933,7 +935,6 @@ validtoken(const char *s) return strlen(s) == TOKLEN && strspn(s, "0123456789abcdef") == TOKLEN; } - /* main */ int main(int argc, char *argv[])