tgit-restrict.c - git-restrict - simple utility for git repo permission management
HTML git clone https://git.parazyd.org/git-restrict
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tgit-restrict.c (2411B)
---
1 /* Copyright (c) 2021-2022 Ivan J. <parazyd@dyne.org>
2 *
3 * This file is part of git-restrict
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License version 3
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 static void die(const char *msg)
23 {
24 fprintf(stderr, "%s\n", msg);
25 exit(1);
26 }
27
28 static char *strdup(const char *s)
29 {
30 size_t sz = strlen(s)+1;
31 char *d = malloc(sz);
32 if (!d) return NULL;
33 return memcpy(d, s, sz);
34 }
35
36 int main(int argc, char *argv[])
37 {
38 char *orig_cmd, *cmd, *repo, *buf;
39 char git_cmd[20 + 256];
40 int i, authorized = 0;
41
42 if (argc < 2)
43 die("usage: git-restrict repo0 repo1 ...");
44
45 if ((orig_cmd = getenv("SSH_ORIGINAL_COMMAND")) == NULL)
46 die("fatal: No $SSH_ORIGINAL_COMMAND in env.");
47
48 if ((repo = strdup(orig_cmd)) == NULL) die("fatal: Internal error.");
49 if ((cmd = strtok(repo, " ")) == NULL) die("fatal: Invalid command.");
50 repo = strtok(NULL, " ");
51
52 if (strcmp("git-upload-pack", cmd) && strcmp("git-receive-pack", cmd))
53 die("fatal: Unauthorized command.");
54
55 /* Repository name should at least be: 'a' */
56 if (repo == NULL || (strlen(repo) < 3))
57 die("fatal: Invalid repository name.");
58
59 /* Remove ' and / prefix and ' suffix */
60 repo++; if (repo[0] == '/') repo++; repo[strlen(repo) - 1] = 0;
61
62 for (i = 1; i < argc; i++) {
63 /* This is so both "foo" and "foo.git" are supported */
64 if ((buf = malloc(strlen(repo) + 4)) == NULL) {
65 perror("malloc");
66 return 1;
67 }
68
69 snprintf(buf, strlen(repo) + 4, "%s.git", argv[i]);
70
71 if (!strcmp(argv[i], repo) || !strcmp(buf, repo)) {
72 authorized = 1;
73 free(buf);
74 break;
75 }
76
77 free(buf);
78 }
79
80 if (!authorized)
81 die("fatal: Access to repository denied.");
82
83 snprintf(git_cmd, strlen(cmd) + strlen(repo) + 4, "%s '%s'", cmd, repo);
84
85 if (execlp("git-shell", "git-shell", "-c", git_cmd, (char *)NULL) == -1)
86 perror("execlp");
87
88 return 1;
89 }