]> oss.titaniummirror.com Git - repo_shell.git/blobdiff - repo_shell.c
Implement * to mean any user or repo
[repo_shell.git] / repo_shell.c
index 6ec08b2f53372ca20251842fc11e5fecce71b7e5..24eb6e20adbdb3e19dde2767aca372ed6a8ac05a 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdbool.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include "ini.h"
 #include "utility.h"
 #include "version.h"
+#include "git_acl.h"
 
 #define CFG_FILE "/etc/repo_shell.cfg"
-#define GIT_ACL_FILE "git_acl.cfg"
 #define SHELL "/bin/bash"
 
 typedef struct {
   char *svn_root;
   char *git_root;
   char *owner;
+  char *git_acl_file;
 } cfg_t;
 
 static cfg_t cfg;
@@ -76,40 +78,18 @@ static int check_ssh_interactive(uid_t uid)
   return 1; /* for now */
 }
 
-static int git_acl(const char *user, const char *repo)
+/* Return true if the user's permissions >= those required */
+static bool git_check_access(const char *cmd, const char *repo,
+    const char *user)
 {
-  /* TODO: Read GIT_ACL_FILE from cfg.owner's home directory.  Look for
-   * the access level afforded user for repo.  A return of 0 means no
-   * access, a return of 1 means read only, and a return of 2 means
-   * read/write.
+  /* What access is required per the incoming command?  Uploading commands
+   * require PERMS_READ_WRITE, while all other commands are assumed to need only
+   * PERMS_READ.
    */
-#if 0
-  struct passwd *pw;
-  char *file;
-  int len = strlen(cfg.owner) + strlen(GIT_ACL_FILE) + 8;
-
-  pw = getpwnam(cfg.owner);
-  if (!pw)
-    die("owner %s has no passwd entry?", cfg.owner);
-  len = strlen(pw->pw_dir) + strlen(GIT_ACL_FILE) + 2;
-  file = xmalloc(sizeof(char) * len);
-  sprintf(file, "%s/%s", pw->pw_dir, GIT_ACL_FILE);
-  fprintf(stderr, "[someday check %s for git ACLs]\n", file);
-  free(file);
-#endif
-  return 2; /* assume read/write for now */
-}
-
-static int git_check_access(const char *cmd, const char *repo, const char *user)
-{
-  /* What access is required per the incoming command?
-   * 0=none, 1=read-only, 2=read-write
-   */
-  int rw = (!strcmp(cmd, "git-upload-pack") ||
-      !strcmp(cmd, "git-upload-archive")) ? 2 : 1;
-
-  /* Return true (1) if the user permissions >= those required */
-  return (git_acl(user, repo) >= rw) ? 1 : 0;
+  perms_t need = !strncmp(cmd, "git-upload", 10) ? PERMS_READ :
+      PERMS_READ_WRITE;
+  perms_t have = git_acl(user, repo, cfg.git_acl_file);
+  return have >= need;
 }
 
 static int do_git_cmd(const char *cmd, char *arg, char *user)
@@ -125,7 +105,7 @@ static int do_git_cmd(const char *cmd, char *arg, char *user)
 
   change_user(cfg.owner);
   if (!git_check_access(cmd, arg, user))
-    die("permission denied");
+    die("insufficient ACL permissions");
 
   nargv[0] = cmd;
   nargv[1] = add_prefix(cfg.git_root, arg);
@@ -180,6 +160,8 @@ static int ini_handler(void* user, const char* section, const char* name,
     pconfig->git_root = xstrdup(value);
   else if (MATCH("core", "owner"))
     pconfig->owner = xstrdup(value);
+  else if (MATCH("core", "git_acl_file"))
+    pconfig->git_acl_file = xstrdup(value);
   else
     return 0;  /* unknown section/name, error */
   return 1;
@@ -220,6 +202,16 @@ int main(int argc, char **argv)
   if (ini_parse(CFG_FILE, ini_handler, &cfg) < 0)
     die("cannot read config file %s", CFG_FILE);
 
+  if (argc == 4 && (!strcmp(argv[1], "-t") ||
+      !strcmp(argv[1], "--test"))) {
+    perms_t p = git_acl(argv[2], argv[3], cfg.git_acl_file);
+    fprintf(stderr,
+        "user '%s' repo '%s' perms '%s'\n  via userid '%s' repoid '%s'\n",
+        argv[2], argv[3], git_acl_perms_as_str(p), git_acl_last_userid(),
+        git_acl_last_repoid());
+    return 0;
+  }
+
   prog = xstrdup(argv[2]);
   if (!strncmp(prog, "git", 3) && isspace(prog[3]))
     /* Accept "git foo" as if the caller said "git-foo". */