diff --git a/.gitignore b/.gitignore
index 9b68d7a..a1ab927 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-*~
-*\#*
obj/
+/.depend
+/git-auth
+*.d
diff --git a/Makefile b/Makefile
index 2c53645..936836c 100644
--- a/Makefile
+++ b/Makefile
@@ -16,21 +16,18 @@
##
PROG = git-auth
-VER = 0.1
+VER = 0.2.1
GIT_SHELL ?= /usr/local/bin/git-shell
-CPPFLAGS = -DSHELL=\"${GIT_SHELL}\"
-DEBUG ?= -g -DDEBUG
+CPPFLAGS = -DGIT_SHELL=\"${GIT_SHELL}\"
+DEBUG ?= -ggdb -DDEBUG
WARNINGS ?= yes
-CDIAGFLAGS ?= -W -Wall -Werror
-LDFLAGS += -W -Wall -Werror
+CDIAGFLAGS ?= -W -Wall -Werror -std=c89 -pedantic
+LDFLAGS += -W -Wall -Werror -std=c89 -pedantic
SRCS = git-auth.c \
rule.c rule.h \
- symbol.c symbol.h \
- symtable.c symtable.h \
- sympackage.c sympackage.h
BINDIR ?= /usr/local/bin
MANDIR ?= /usr/local/man/man
@@ -40,9 +37,6 @@ build: ${PROG}
DISTDIR = ${PROG}-${VER}
DIST = ${DISTDIR}.tar.gz
-dist: ${DIST}
- rsync -tP ${DIST} lowh-dist@lowh.net:dist/LowH/${PROG}/
-
DISTFILES = ${SRCS} ${PROG}.1 README.md Makefile
${DIST}: ${DISTFILES}
diff --git a/README.md b/README.md
index 2d69f4b..47232bf 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,26 @@
# GIT-AUTH
+
## Synopsis
- GIT_AUTH_ID=ID git-auth COMMAND [ARGS ...]</td>
+ GIT_AUTH_ID=ID git-auth COMMAND [ARGS ...]
+
## Description
-**git-auth** starts by reading rules from /etc/git-auth.conf, one rule
+**git-auth** starts by reading rules from /etc/git/auth.conf, one rule
per line. Empty lines and lines starting with # are ignored. Each rule
is made of tokens separated by one or more spaces.
**git-auth** executes COMMAND and ARGS using execvp if the requested ID,
-COMMAND and ARGS match any of the rules defined in /etc/git-auth.conf.
+COMMAND and ARGS match any of the rules defined in /etc/git/auth.conf.
**git-auth** matches a rule by matching all the rule's tokens with ID,
COMMAND and ARGS in order. Comparison is case sensitive.
A wildcard token "*" matches any string.
+
## Environment
* **GIT_AUTH_ID** : an arbitrary token to match with the rules.
@@ -25,7 +28,48 @@ This is usually set for each public key in /home/git/.ssh/authorized_keys
with
environment="GIT_AUTH_ID=..." ssh-rsa ...
+
+## Configuration
+
+Access control rules for each git repository go into
+`/etc/git/auth.conf`.
+
+The syntax of this file is one rule per line.
+Each rule is composed of symbols separated by spaces.
+In order :
+ - A **GIT_AUTH_ID** value that was set in
+ `/home/git/.ssh/authorized_keys`.
+ - Permissions, either `rw` or `r`.
+ - A repository path, relative to `/home/git`,
+ example: `cl-adams/adams.git`
+
+
## Files
- * /etc/git-auth.conf
+ * /etc/git/auth.conf
* /home/git/.ssh/authorized_keys
+
+
+# See also
+
+[kmxgit](https://git.kmx.io/kmx.io/kmxgit)
+is a web interface on top of git-auth written in Elixir / Phoenix.
+
+
+# Copying
+
+git-auth - restrict git commands
+
+Copyright 2012,2021 Thomas de Grivel <thoxdg@gmail.com>
+
+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.
diff --git a/git-auth.1 b/git-auth.1
index efe2f49..1a6747a 100644
--- a/git-auth.1
+++ b/git-auth.1
@@ -8,18 +8,18 @@
.Nm GIT_AUTH_ID=ID git-auth COMMAND [ARGS ...]
.Sh DESCRIPTION
.Nm
-starts by reading rules from /etc/git-auth.conf, one rule per line.
+starts by reading rules from /etc/git/auth.conf, one rule per line.
Empty lines and lines starting with # are ignored.
Each rule is made of tokens separated by one or more spaces.
-
+.Pp
.Nm
executes COMMAND and ARGS using execvp if the requested ID, COMMAND and ARGS
match any of the rules defined in /etc/git-auth.conf.
-
+.Pp
.Nm
matches a rule by matching all the rule's tokens with
ID, COMMAND and ARGS in order. Comparison is case sensitive.
-
+.Pp
A wildcard token "*" matches any string.
.Sh ENVIRONMENT
GIT_AUTH_ID :
@@ -28,6 +28,6 @@ This is usually set for each public key in /home/git/.ssh/authorized_keys
with
.Nm environment="GIT_AUTH_ID=..."
.Sh FILES
-/etc/git-auth.conf
-
+/etc/git/auth.conf
+.Pp
/home/git/.ssh/authorized_keys
diff --git a/git-auth.c b/git-auth.c
index 8cbac96..6d43175 100644
--- a/git-auth.c
+++ b/git-auth.c
@@ -1,6 +1,6 @@
/*
* git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
+ * Copyright 2012,2021 Thomas de Grivel <thoxdg@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,226 +15,265 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <stdarg.h>
-#include <string.h>
+#include <assert.h>
#include <err.h>
#include <errno.h>
-#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
#include <unistd.h>
-#include <assert.h>
-
-#include "sympackage.h"
#include "rule.h"
-#ifndef ENV_AUTH_ID
-# define ENV_AUTH_ID "GIT_AUTH_ID"
+#ifndef GIT_AUTH_ID_ENV
+#define GIT_AUTH_ID_ENV "GIT_AUTH_ID"
#endif
-#ifndef SHELL
-# define SHELL "git-shell"
+#ifndef GIT_SHELL
+#define GIT_SHELL "git-shell"
#endif
-s_sympackage g_sympkg;
+#define CMD_BUFSZ 2048
+#define LOG_BUFSZ 2048
-void stracat (char *buf, size_t bufsiz, const char **str_array, size_t sasiz)
+static void stracat (char *buf, size_t bufsz, int argc, const char **argv)
{
- size_t b = 0;
- size_t a;
- assert(buf);
- assert(bufsiz);
- assert(str_array);
- assert(sasiz);
- for (a = 0; a < sasiz && b < bufsiz; a++) {
- if (a)
- buf[b++] = ' ';
- b += strlcpy(buf + b, str_array[a], bufsiz - b);
- }
+ size_t b = 0;
+ int a;
+ assert(buf);
+ assert(bufsz);
+ assert(argc);
+ assert(argv);
+ for (a = 0; a < argc; a++) {
+ const char *arg;
+ if (b >= bufsz - strlen(argv[a]) - 2) {
+ errno = ENOMEM;
+ err(1, "stracat");
+ }
+ if (a)
+ buf[b++] = ' ';
+ arg = argv[a];
+ while (*arg)
+ buf[b++] = *(arg++);
+ }
+ buf[b] = 0;
}
-void log_args (const char *op, int argc, const char **argv)
+static void stracat_quoted (char *buf, size_t bufsz, int argc, const char **argv)
{
- char msg[2048];
- stracat(msg, sizeof(msg), argv, argc);
- syslog(LOG_INFO, "%s %s", op, msg);
+ size_t b = 0;
+ int a;
+ assert(buf);
+ assert(bufsz);
+ assert(argc);
+ assert(argv);
+ for (a = 0; a < argc; a++) {
+ const char *arg;
+ if (b >= bufsz - strlen(argv[a]) * 2 - 2) {
+ errno = ENOMEM;
+ err(1, "stracat");
+ }
+ if (a)
+ buf[b++] = ' ';
+ buf[b++] = '"';
+ arg = argv[a];
+ while (*arg) {
+ char c = *(arg++);
+ if (c == '"')
+ buf[b++] = '\\';
+ buf[b++] = c;
+ }
+ buf[b++] = '"';
+ }
+ buf[b] = 0;
}
-void log_rule (const char *op, s_symtable *cmd)
+static void log_args (const char *op, int argc, const char **argv)
{
- char msg[2048];
- size_t m = 0;
- assert(cmd);
- m += strlcpy(msg + m, ENV_AUTH_ID, sizeof(msg) - m);
- msg[m++] = '=';
- stracat(msg + m, sizeof(msg) - m, cmd->sym, cmd->count);
- syslog(LOG_INFO, "%s %s", op, msg);
+ char msg[2048];
+ stracat(msg, sizeof(msg), argc, argv);
+ syslog(LOG_INFO, "%s %s", op, msg);
}
-void log_cmd (const char *op, s_symtable *cmd)
+static void log_rule (const char *op, s_rule *rule)
{
- char msg[2048];
- assert(cmd);
- stracat(msg, sizeof(msg), cmd->sym, cmd->count);
- syslog(LOG_INFO, "%s %s", op, msg);
-}
-t_sym read_symbol (const char **buf)
-{
- const char *b = *buf;
- const char *start;
- while (isspace(*b))
- b++;
- start = b;
- while (*b && !isspace(*b))
- b++;
- *buf = b;
- return (start == b) ? NULL :
- sympackage_intern_n(&g_sympkg, start, b - start);
+ char msg[LOG_BUFSZ];
+ size_t m = 0;
+ const char *mode = "?";
+ m += strlcpy(msg + m, GIT_AUTH_ID_ENV, sizeof(msg) - m);
+ if (m >= LOG_BUFSZ - 2)
+ goto overflow;
+ msg[m++] = '=';
+ m += strlcpy(msg + m, rule->user, sizeof(msg) - m);
+ if (m >= LOG_BUFSZ - 2)
+ goto overflow;
+ msg[m++] = ' ';
+ assert(1 <= rule->mode && rule->mode <= 3);
+ switch (rule->mode) {
+ case 1: mode = "r"; break;
+ case 2: mode = "w"; break;
+ case 3: mode = "rw"; break;
+ default: fprintf(stderr, "log_rule: invalid mode: %d\n", rule->mode);
+ }
+ m += strlcpy(msg + m, mode, sizeof(msg) - m);
+ if (m >= LOG_BUFSZ - 2)
+ goto overflow;
+ msg[m++] = ' ';
+ m += strlcpy(msg + m, rule->path, sizeof(msg) - m);
+ syslog(LOG_INFO, "%s %s", op, msg);
+ return;
+ overflow:
+ fprintf(stderr, "git-auth: log_rule: buffer overflow !\n");
}
-void rule_read (s_rule *r, const char *buf)
+/*
+static void log_rules (s_rule rules[RULES_MAX])
{
- const char *b = buf;
- t_sym s;
- while ((s = read_symbol(&b)) && (*s != '#')) {
- syslog(LOG_DEBUG, "SYMBOL %s", s);
- rule_add(r, s);
- }
+ int r = 0;
+ while (rules[r].user) {
+ char buf[16];
+ snprintf(buf, 15, "%d", r);
+ log_rule(buf, &rules[r]);
+ r++;
+ }
}
+*/
-void rules_read (s_rules *rr, const char *path)
+static void log_cmd (const char *op, int argc, const char **argv)
{
- syslog(LOG_DEBUG, "READ %s", path);
- FILE *fp = fopen(path, "r");
- if (!fp) {
- syslog(LOG_ERR, "rules_read: %s: %s", path, strerror(errno));
- err(3, "rules_read: %s", path);
- }
- char line[2048];
- while (fgets(line, sizeof(line) - 4, fp)) {
- s_rule r;
- syslog(LOG_DEBUG, "LINE %s", line);
- rule_init(&r);
- rule_read(&r, line);
- if (r.count >= 2) {
- log_rule("RULE", &r);
- rules_add(rr, &r);
- }
- else if (r.count == 1)
- syslog(LOG_WARNING, "invalid rule: %s", line);
- }
- if (ferror(fp)) {
- syslog(LOG_ERR, "rules_read: %s: %s", path, strerror(errno));
- fclose(fp);
- err(3, "rules_read: %s", path);
- }
- fclose(fp);
+ char msg[LOG_BUFSZ];
+ stracat(msg, LOG_BUFSZ, argc, argv);
+ syslog(LOG_INFO, "%s %s", op, msg);
}
-int rule_match (s_rule *r, s_symtable *cmd)
+/*
+int unquote (char *buf, size_t bufsz, const char *str)
{
- assert(r);
- assert(cmd);
- if (r->count > cmd->count)
- return 0;
- size_t i = r->count;
- t_sym *rs = r->sym;
- t_sym *cs = cmd->sym;
- static t_sym sym_wild = 0;
- if (!sym_wild)
- sym_wild = sympackage_intern_static(&g_sympkg, "*");
- while (i--) {
- if (*rs != sym_wild && *rs != *cs)
- return 0;
- syslog(LOG_DEBUG, "%s %s", *rs, *cs);
- rs++;
- cs++;
- }
- return 1;
+ size_t len = strlen(str);
+ assert(len < bufsz);
+ if (str[0] == '\'' && len > 1 && str[len - 1] == '\'') {
+ strlcpy(buf, str + 1, bufsz);
+ buf[len - 2] = 0;
+ return 1;
+ }
+ strlcpy(buf, str, bufsz);
+ return 0;
}
-int auth (s_rules *rr, s_symtable *cmd)
+static int rule_match_path (const char *rule_path, const char *arg_path)
{
- size_t i = rr->count;
- s_rule *r = rr->rule;
- while (i--) {
- if (rule_match(r, cmd))
- return 1;
- r++;
- }
- return 0;
+ char rp[1024];
+ char ap[1024];
+ unquote(rp, sizeof(rp), rule_path);
+ unquote(ap, sizeof(ap), arg_path);
+ return strcmp(rp, ap) == 0;
}
+*/
-void init_package ()
+static int rule_match (s_rule *rule, int argc, const char **argv)
{
- sympackage_init(&g_sympkg);
- sympackage_intern_static(&g_sympkg, "*");
+ assert(rule);
+ assert(argc);
+ assert(argv);
+ if (argc != 3)
+ return 0;
+ if (strcmp(rule->user, argv[0]))
+ return 0;
+ if (!strcmp(argv[1], "git-upload-pack") && !(rule->mode & 1))
+ return 0;
+ else if (!strcmp(argv[1], "git-receive-pack") && !(rule->mode & 2))
+ return 0;
+ if (strcmp(rule->path, argv[2]))
+ return 0;
+ return 1;
}
-void usage (const char *argv0)
+static int auth (s_rule rules[RULES_MAX], int argc, const char **argv)
{
- fprintf(stderr, "Usage: %s=ID %s -c COMMAND\n", ENV_AUTH_ID, argv0);
- exit(5);
+ int r = 0;
+ while (rules[r].user) {
+ /* log_rule("MATCH", &rules[r]); */
+ if (rule_match(&rules[r], argc, argv)) {
+ log_rule("ALLOW", &rules[r]);
+ return 1;
+ }
+ /* else
+ log_rule("DENY", &rules[r]); */
+ r++;
+ }
+ return 0;
}
-void cmd_init (s_symtable *cmd, t_sym id, const char *arg)
+static void cleanup (void)
{
- rule_init(cmd);
- rule_add(cmd, id);
- rule_read(cmd, arg);
+ closelog();
}
-void cleanup ()
+static void exec_cmd (int argc, const char **argv)
{
- closelog();
- sympackage_free(&g_sympkg);
+ char buf[CMD_BUFSZ];
+ const char *cmd_argv[4];
+ assert(argc);
+ assert(argv);
+ cmd_argv[0] = GIT_SHELL;
+ cmd_argv[1] = "-c";
+ stracat(buf, CMD_BUFSZ, argc - 1, argv + 1);
+ cmd_argv[2] = buf;
+ cmd_argv[3] = NULL;
+ log_cmd("EXEC", 3, cmd_argv);
+ cleanup();
+ execvp(cmd_argv[0], (char *const *) cmd_argv);
+ err(1, "%s", cmd_argv[0]);
}
-void exec_cmd (const s_symtable *cmd)
+static void usage (const char *argv0)
{
- s_symtable xc;
- assert(cmd);
- symtable_init(&xc);
- symtable_add(&xc, SHELL);
- symtable_add(&xc, "-c");
- char buf[2048];
- stracat(buf, sizeof(buf), cmd->sym + 1, cmd->count - 1);
- symtable_add(&xc, buf);
- log_cmd("EXEC", &xc);
- cleanup();
- execvp(xc.sym[0], (char **)xc.sym);
- syslog(LOG_ERR, "execvp: %s", strerror(errno));
- err(2, "execvp");
+ fprintf(stderr, "Usage: %s=ID %s -c GIT_COMMAND PATH\n",
+ GIT_AUTH_ID_ENV, argv0);
+ exit(1);
}
int main (int argc, char **argv)
{
- s_rules rr;
- if (argv[argc])
- err(1, "bad argument list");
- if (argc != 3)
- usage(argv[0]);
- if (strcmp(argv[1], "-c"))
- usage(argv[0]);
- openlog(argv[0], LOG_PID, LOG_AUTH);
- log_args("NEW", argc, (const char **)argv);
- init_package();
- const char *env_auth_id = getenv(ENV_AUTH_ID);
- t_sym id = sympackage_intern(&g_sympkg, env_auth_id ? env_auth_id : "");
- s_symtable cmd;
- cmd_init(&cmd, id, argv[2]);
- rules_init(&rr);
- rules_read(&rr, "/etc/git-auth.conf");
- int auth_ok = auth(&rr, &cmd);
- rules_free(&rr);
- log_rule(auth_ok ? "ALLOW" : "DENY", &cmd);
- if (auth_ok) {
- exec_cmd(&cmd);
- // never reached
- }
- log_rule("DENY", &cmd);
- cleanup();
- return 1;
+ char buf[LOG_BUFSZ];
+ char *bs;
+ s_rule rules[RULES_MAX];
+ const char *git_auth_id;
+ int auth_ok;
+ const char *cmd_argv[3];
+ if (argc != 3) {
+ char buf[LOG_BUFSZ];
+ fprintf(stderr, "git-auth: wrong number of arguments: %d.\n", argc);
+ stracat_quoted(buf, sizeof(buf), argc, (const char **) argv);
+ fprintf(stderr, "%s\n", buf);
+ usage(argv[0]);
+ }
+ if (strcmp(argv[1], "-c")) {
+ fprintf(stderr, "expected -c as first argument.\n");
+ usage(argv[0]);
+ }
+ git_auth_id = getenv(GIT_AUTH_ID_ENV);
+ if (!git_auth_id) {
+ fprintf(stderr, "missing %s.\n", GIT_AUTH_ID_ENV);
+ usage(argv[0]);
+ }
+ cmd_argv[0] = git_auth_id;
+ strlcpy(buf, argv[2], LOG_BUFSZ);
+ cmd_argv[1] = buf;
+ bs = strchr(buf, ' ');
+ *bs++ = 0;
+ cmd_argv[2] = bs;
+ openlog(argv[0], LOG_PID, LOG_AUTH);
+ log_args("NEW", argc, (const char **) argv);
+ read_rules(rules, "/etc/git/auth.conf");
+ /* log_rules(rules); */
+ auth_ok = auth(rules, 3, cmd_argv);
+ log_cmd(auth_ok ? "ALLOW" : "DENY", 3, cmd_argv);
+ if (auth_ok) {
+ exec_cmd(3, cmd_argv);
+ /* never reached */
+ }
+ cleanup();
+ return 1;
}
diff --git a/rule.c b/rule.c
index 8a5adbe..16afde0 100644
--- a/rule.c
+++ b/rule.c
@@ -1,6 +1,6 @@
/*
* git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
+ * Copyright 2021 Thomas de Grivel <thoxdg@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,44 +16,168 @@
*/
#include <assert.h>
-#include <string.h>
#include <err.h>
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "rule.h"
-void rules_init (s_rules *rr)
+#define BUFSZ 1024
+
+void skip_whitespace (char **b)
{
- assert(rr);
- rr->count = 0;
- rr->size = 32;
- if (!(rr->rule = calloc(rr->size, sizeof(s_rule))))
- err(10, "rules calloc");
+ while (**b && strchr(" \f\r\t\v", **b))
+ (*b)++;
}
-void rules_free (s_rules *rr)
+int rule_parse_user (s_rule *rule, char **b)
{
- assert(rr);
- int i = rr->count;
- while (i--)
- rule_free(rr->rule + i);
- free(rr->rule);
- bzero(rr, sizeof(s_rules));
+ char *s;
+ char *t;
+ size_t len;
+ char *user;
+ s = strchr(*b, ' ');
+ t = strchr(*b, '\t');
+ if (s && t && t < s)
+ s = t;
+ if (!s) {
+ fprintf(stderr, "%s:%d: invalid rule user.\n",
+ rule->src_path, rule->src_line);
+ return 1;
+ }
+ *s = 0;
+ len = s - *b + 1;
+ user = malloc(len);
+ strlcpy(user, *b, len);
+ *b = s + 1;
+ rule->user = user;
+ return 0;
}
-void rules_enlarge (s_rules *rr)
+int rule_parse_mode (s_rule *rule, char **b)
{
- assert(rr);
- rr->size += rr->size < 1024 ? rr->size : 1024;
- if (!(rr->rule = realloc(rr->rule, rr->size)))
- err(10, "rules realloc");
- assert(rr->size > rr->count);
+ char *s;
+ char *t;
+ skip_whitespace(b);
+ s = strchr(*b, ' ');
+ t = strchr(*b, '\t');
+ if (s && t && t < s)
+ s = t;
+ if (!s) {
+ fprintf(stderr, "%s:%d: invalid rule mode.\n",
+ rule->src_path, rule->src_line);
+ return 1;
+ }
+ *s = 0;
+ if (!strcmp(*b, "r")) {
+ rule->mode = 1;
+ *b += 2;
+ return 0;
+ }
+ if (!strcmp(*b, "w")) {
+ rule->mode = 2;
+ *b += 2;
+ return 0;
+ }
+ if (!strcmp(*b, "rw")) {
+ rule->mode = 3;
+ *b += 3;
+ return 0;
+ }
+ if (!strcmp(*b, "*")) {
+ rule->mode = 3;
+ *b += 2;
+ return 0;
+ }
+ fprintf(stderr, "%s:%d: invalid rule mode.\n",
+ rule->src_path, rule->src_line);
+ return 1;
}
-const s_rule * rules_add (s_rules *rr, const s_rule *r)
+int rule_parse_path (s_rule *rule, char **b)
+{
+ char *c;
+ size_t len;
+ char *path;
+ skip_whitespace(b);
+ if (!*b || !strcmp(*b, "'") || !strcmp(*b, "''")) {
+ fprintf(stderr, "%s:%d: invalid rule path.\n",
+ rule->src_path, rule->src_line);
+ return 1;
+ }
+ c = *b + strlen(*b) - 1;
+ while (strchr(" \f\r\t\v", *c))
+ c--;
+ c++;
+ *c = 0;
+ len = c - *b + 1;
+ path = malloc(len);
+ strlcpy(path, *b, len);
+ rule->path = path;
+ return 0;
+}
+
+int rule_parse (s_rule *rule, char *buf, const char *path, int line)
+{
+ char *b = buf;
+ skip_whitespace(&b);
+ if (*b == 0 || *b == '#')
+ return 1;
+ rule->src_path = path;
+ rule->src_line = line;
+ if (rule_parse_user(rule, &b))
+ return 2;
+ if (rule_parse_mode(rule, &b))
+ return 2;
+ if (rule_parse_path(rule, &b))
+ return 2;
+ return 0;
+}
+
+
+int read_rules (s_rule rules[RULES_MAX], const char *path)
{
- assert(rr);
- if (rr->count == rr->size)
- rules_enlarge(rr);
- rr->rule[rr->count] = *r;
- return rr->rule + rr->count++;
+ FILE *fp;
+ int line;
+ int r;
+ char buf[BUFSZ];
+ char *nl;
+ int error = 0;
+ if (!(fp = fopen(path, "r")))
+ err(1, "%s", path);
+ line = 0;
+ r = 0;
+ while (!feof(fp)) {
+ int i;
+ line++;
+ if (!fgets(buf, BUFSZ, fp)) {
+ if (ferror(fp))
+ err(1, "%s", path);
+ bzero(&rules[r], sizeof(s_rule));
+ if (error)
+ exit(1);
+ /* fprintf(stderr, "fgets NULL. r: %d\n", r); */
+ return r;
+ }
+ if (!(nl = strchr(buf, '\n'))) {
+ fprintf(stderr, "%s:%d: line too long.\n", path, line);
+ exit(1);
+ }
+ *nl = 0;
+ if (r >= RULES_MAX - 1) {
+ fprintf(stderr, "%s: maximum number of rules "
+ "exceeded.\n", path);
+ exit(1);
+ }
+ i = rule_parse(&rules[r], buf, path, line);
+ if (i == 0)
+ r++;
+ else if (i == 2)
+ error = 1;
+ }
+ bzero(&rules[r], sizeof(s_rule));
+ if (error)
+ exit(1);
+ /* fprintf(stderr, "EOF. r: %d\n", r); */
+ return r;
}
diff --git a/rule.h b/rule.h
index f76db0a..7c83f57 100644
--- a/rule.h
+++ b/rule.h
@@ -1,6 +1,6 @@
/*
* git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
+ * Copyright 2021 Thomas de Grivel <thoxdg@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,26 +18,23 @@
#ifndef RULE_H
#define RULE_H
-#include <stdlib.h>
+/* one rule per user, mode, path */
-#include "symtable.h"
+typedef struct rule {
+ const char *user;
+#define RULE_MODE_R 1
+#define RULE_MODE_W 2
+#define RULE_MODE_RW 3
+ int mode;
+ const char *path;
+ const char *src_path;
+ int src_line;
+} s_rule;
-typedef s_symtable s_rule;
+/* null terminated array of null terminated arrays of rules. */
-#define rule_init(r) symtable_init(r)
-#define rule_free symtable_free
-#define rule_free_all symtable_free_all
-#define rule_add(r, s) symtable_add(r, s)
+#define RULES_MAX (1024 * 10)
-typedef struct rules {
- size_t count;
- size_t size;
- s_rule *rule;
-} s_rules;
-
-void rules_init (s_rules *rr);
-void rules_free (s_rules *rr);
-void rules_enlarge (s_rules *rr);
-const s_rule * rules_add (s_rules *rr, const s_rule *r);
+int read_rules (s_rule rules[RULES_MAX], const char *path);
#endif
diff --git a/symbol.c b/symbol.c
deleted file mode 100644
index 8170682..0000000
--- a/symbol.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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 <string.h>
-#include <stdlib.h>
-#include <err.h>
-
-#include "symbol.h"
-
-char * string_clone (const char *string)
-{
- if (string) {
- size_t len = strlen(string);
- char *clone = malloc(len + 1);
- if (!clone)
- err(10, "string_clone malloc");
- strlcpy(clone, string, len + 1);
- return clone;
- }
- return NULL;
-}
-
-char * string_clone_n (const char *string, size_t len)
-{
- if (string) {
- char *clone = malloc(len + 1);
- if (!clone)
- err(10, "string_clone_n malloc");
- strlcpy(clone, string, len + 1);
- return clone;
- }
- return NULL;
-}
diff --git a/symbol.h b/symbol.h
deleted file mode 100644
index fcd052a..0000000
--- a/symbol.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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.
- */
-
-#ifndef SYMBOL_H
-#define SYMBOL_H
-
-typedef const char *t_sym;
-
-char * string_clone (const char *string);
-char * string_clone_n (const char *string, size_t len);
-
-#endif
diff --git a/sympackage.c b/sympackage.c
deleted file mode 100644
index fd82c9a..0000000
--- a/sympackage.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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 <assert.h>
-#include <string.h>
-
-#include "sympackage.h"
-
-void sympackage_init (s_sympackage *sp)
-{
- assert(sp);
- symtable_init(&sp->static_table);
- symtable_init(&sp->dynamic_table);
-}
-
-void sympackage_free (s_sympackage *sp)
-{
- assert(sp);
- symtable_free(&sp->static_table);
- symtable_free_all(&sp->dynamic_table);
-}
-
-t_sym sympackage_intern (s_sympackage *sp, const char *string)
-{
- assert(sp);
- t_sym s = symtable_find(&sp->static_table, string);
- if (!s)
- s = symtable_find(&sp->dynamic_table, string);
- if (!s)
- s = symtable_add(&sp->dynamic_table, string_clone(string));
- return s;
-}
-
-t_sym sympackage_intern_n (s_sympackage *sp, const char *string, size_t len)
-{
- assert(sp);
- t_sym s = symtable_find_n(&sp->static_table, string, len);
- if (!s)
- s = symtable_find_n(&sp->dynamic_table, string, len);
- if (!s)
- s = symtable_add(&sp->dynamic_table, string_clone_n(string, len));
- return s;
-}
-
-t_sym sympackage_intern_static (s_sympackage *sp, const char *string)
-{
- assert(sp);
- t_sym s = symtable_find(&sp->static_table, string);
- if (!s)
- s = symtable_add(&sp->static_table, string);
- return s;
-}
diff --git a/sympackage.h b/sympackage.h
deleted file mode 100644
index 056ca5e..0000000
--- a/sympackage.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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.
- */
-
-#ifndef SYMPACKAGE_H
-#define SYMPACKAGE_H
-
-#include "symtable.h"
-
-typedef struct sympackage {
- s_symtable static_table;
- s_symtable dynamic_table;
-} s_sympackage;
-
-void sympackage_init (s_sympackage *sp);
-void sympackage_free (s_sympackage *sp);
-t_sym sympackage_intern (s_sympackage *sp, const char *string);
-t_sym sympackage_intern_n (s_sympackage *sp, const char *string, size_t len);
-t_sym sympackage_intern_static (s_sympackage *sp, const char *string);
-
-#endif
diff --git a/symtable.c b/symtable.c
deleted file mode 100644
index 3a3c301..0000000
--- a/symtable.c
+++ /dev/null
@@ -1,127 +0,0 @@
-
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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 <assert.h>
-#include <string.h>
-#include <err.h>
-
-#include "symtable.h"
-
-void symtable_init (s_symtable *st)
-{
- assert(st);
- st->count = 0;
- st->size = 128;
- if (!(st->sym = calloc(st->size, sizeof(t_sym))))
- err(10, "symtable_init calloc");
-}
-
-s_symtable * symtable_copy (s_symtable *dest, s_symtable *st)
-{
- assert(dest);
- assert(st);
- dest->count = st->count;
- dest->size = st->size;
- if (!(dest->sym = calloc(dest->size, sizeof(t_sym))))
- err(10, "symtable_copy calloc");
- return dest;
-}
-
-void symtable_free (s_symtable *st)
-{
- assert(st);
- free(st->sym);
- bzero(st, sizeof(s_symtable));
-}
-
-void symtable_free_all (s_symtable *st)
-{
- assert(st);
- int i = st->count;
- while (i--)
- free((void*)st->sym[i]);
- free(st->sym);
- bzero(st, sizeof(s_symtable));
-}
-
-void symtable_enlarge (s_symtable *st)
-{
- assert(st);
- st->size += st->size < 1024 ? st->size : 1024;
- if (!(st->sym = realloc(st->sym, st->size)))
- err(10, "symtable realloc");
- assert(st->size > st->count);
-}
-
-t_sym symtable_find (s_symtable *st, const char *string)
-{
- assert(st);
- t_sym *s = st->sym;
- int i = st->count;
- while (i--) {
- if ((*s == string) || (string && !strcmp(string, *s)))
- return *s;
- s++;
- }
- return NULL;
-}
-
-int strcmp_n (const char *a, const char *b, size_t len_b)
-{
- const unsigned char *aa = (const unsigned char *) a;
- const unsigned char *bb = (const unsigned char *) b;
- while (len_b && *aa == *bb && *aa) {
- aa++;
- bb++;
- len_b--;
- }
- if ((!*aa && !len_b) || (*aa == *bb))
- return 0;
- if (!*aa || *aa < *bb)
- return -1;
- return 1;
-}
-
-t_sym symtable_find_n (s_symtable *st, const char *string, size_t len)
-{
- assert(st);
- t_sym *s = st->sym;
- int i = st->count;
- while (i--) {
- if (*s == string || (string && len && !strcmp_n(*s, string, len)))
- return *s;
- s++;
- }
- return NULL;
-}
-
-t_sym symtable_add (s_symtable *st, t_sym sym)
-{
- assert(st);
- if (st->count == st->size)
- symtable_enlarge(st);
- return st->sym[st->count++] = sym;
-}
-
-t_sym symtable_intern (s_symtable *st, const char *string)
-{
- t_sym s = symtable_find(st, string);
- if (!s)
- s = symtable_add(st, string);
- return s;
-}
diff --git a/symtable.h b/symtable.h
deleted file mode 100644
index 95f45dc..0000000
--- a/symtable.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * git-auth - restrict git commands
- * Copyright 2012 Thomas de Grivel <billitch@gmail.com>
- *
- * 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.
- */
-
-#ifndef SYMTABLE_H
-#define SYMTABLE_H
-
-#include <stdlib.h>
-
-#include "symbol.h"
-
-typedef struct symtable {
- size_t count;
- size_t size;
- t_sym *sym;
-} s_symtable;
-
-void symtable_init (s_symtable *st);
-s_symtable * symtable_copy (s_symtable *dest, s_symtable *st);
-void symtable_free (s_symtable *st);
-void symtable_free_all (s_symtable *st);
-void symtable_enlarge (s_symtable *st);
-t_sym symtable_find (s_symtable *st, const char *string);
-t_sym symtable_find_n (s_symtable *st, const char *string, size_t len);
-t_sym symtable_add (s_symtable *st, t_sym sym);
-t_sym symtable_intern (s_symtable *st, const char *string);
-
-#endif