git-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 }