URI: 
       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 }