commit 4b3827cd43394b89d2af822dcd1d9a9179c1ee10 from: Stefan Sperling date: Sat Jul 08 08:37:08 2023 UTC make gitwrapper ignore 'permission denied' for repository paths We recommend that gotsh users should not have direct filesystem access to repositories served by gotd. Which means admins will be setting things up as follows if public read-access should be denied: chown _gotd /git chmod 700 /git su -m _gotd -c 'gotadmin init /git/repo.git" However, gitwrapper would error out when repositories listed in gotd.conf were inaccessible to the user invoking gitwrapper: git-upload-pack: /etc/gotd.conf:2: realpath /git/repo.git: Permission denied Make gitwrapper ignore such errors as they are expected in this situation. While here, add a PROC_GITWRAPPER process ID for use as a global variable parse.y can check while special-casing any specific behaviour required by gitwrapper. (The worse alternative would have been adding a new global variable to parse.y just to control the behaviour on realpath errors.) ok op@ commit - 2df845d59f19a7c87fc48af1f9d4124e57ebf2b0 commit + 4b3827cd43394b89d2af822dcd1d9a9179c1ee10 blob - 1ed8d3dc9b6ae29d105bff2710d33de54cf0bc13 blob + 28645f07dc93480582fce4b5f7dea5813b028a23 --- gitwrapper/gitwrapper.c +++ gitwrapper/gitwrapper.c @@ -131,7 +131,7 @@ main(int argc, char *argv[]) confpath = getenv("GOTD_CONF_PATH"); if (confpath == NULL) confpath = GOTD_CONF_PATH; - parse_config(confpath, PROC_GOTD, &gotd, 0); + parse_config(confpath, PROC_GITWRAPPER, &gotd); error = apply_unveil(myserver); if (error) blob - 68a99a122229289490584888ded7f2beb2d99042 blob + 4432aec44c71cf0db3723fa870ba885b23ddd037 --- gotd/gotd.c +++ gotd/gotd.c @@ -729,7 +729,8 @@ static const char *gotd_proc_names[PROC_MAX] = { "session_read", "session_write", "repo_read", - "repo_write" + "repo_write", + "gitwrapper" }; static void @@ -1858,7 +1859,7 @@ main(int argc, char **argv) if (geteuid() && (proc_id == PROC_GOTD || proc_id == PROC_LISTEN)) fatalx("need root privileges"); - if (parse_config(confpath, proc_id, &gotd, 1) != 0) + if (parse_config(confpath, proc_id, &gotd) != 0) return 1; pw = getpwnam(gotd.user_name); blob - e902d6f53b03f7682202e2b9b3d0af5fc28c25b6 blob + acb40dee8cd351b48669c3c3247c42ed5f44501b --- gotd/gotd.h +++ gotd/gotd.h @@ -40,6 +40,7 @@ enum gotd_procid { PROC_SESSION_WRITE, PROC_REPO_READ, PROC_REPO_WRITE, + PROC_GITWRAPPER, PROC_MAX, }; @@ -442,7 +443,7 @@ struct gotd_imsg_auth { uint32_t client_id; }; -int parse_config(const char *, enum gotd_procid, struct gotd *, int); +int parse_config(const char *, enum gotd_procid, struct gotd *); struct gotd_repo *gotd_find_repo_by_name(const char *, struct gotd *); struct gotd_repo *gotd_find_repo_by_path(const char *, struct gotd *); struct gotd_uid_connection_limit *gotd_find_uid_connection_limit( blob - a3860760379f26a53fcf3788e84f9efb36efbdd3 blob + cc7231514a823861b662e419be141a4492c833fd --- gotd/parse.y +++ gotd/parse.y @@ -293,7 +293,8 @@ repository : REPOSITORY STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || - gotd_proc_id == PROC_REPO_WRITE) { + gotd_proc_id == PROC_REPO_WRITE || + gotd_proc_id == PROC_GITWRAPPER) { new_repo = conf_new_repo($2); } free($2); @@ -304,7 +305,8 @@ repository : REPOSITORY STRING { repoopts1 : PATH STRING { if (gotd_proc_id == PROC_GOTD || gotd_proc_id == PROC_AUTH || - gotd_proc_id == PROC_REPO_WRITE) { + gotd_proc_id == PROC_REPO_WRITE || + gotd_proc_id == PROC_GITWRAPPER) { if (!got_path_is_absolute($2)) { yyerror("%s: path %s is not absolute", __func__, $2); @@ -312,16 +314,28 @@ repoopts1 : PATH STRING { YYERROR; } if (realpath($2, new_repo->path) == NULL) { - yyerror("realpath %s: %s", $2, - strerror(errno)); /* - * Give admin a chance to create - * missing repositories at run-time. + * To give admins a chance to create + * missing repositories at run-time + * we only warn about ENOENT here. + * + * And ignore 'permission denied' when + * running in gitwrapper. Users may be + * able to access this repository via + * gotd regardless. */ - if (errno != ENOENT) { + if (errno == ENOENT) { + yyerror("realpath %s: %s", $2, + strerror(errno)); + } else if (errno != EACCES || + gotd_proc_id != PROC_GITWRAPPER) { + yyerror("realpath %s: %s", $2, + strerror(errno)); free($2); YYERROR; - } else if (strlcpy(new_repo->path, $2, + } + + if (strlcpy(new_repo->path, $2, sizeof(new_repo->path)) >= sizeof(new_repo->path)) yyerror("path too long"); @@ -740,10 +754,11 @@ closefile(struct file *xfile) int parse_config(const char *filename, enum gotd_procid proc_id, - struct gotd *env, int require_config_file) + struct gotd *env) { struct sym *sym, *next; struct gotd_repo *repo; + int require_config_file = (proc_id != PROC_GITWRAPPER); memset(env, 0, sizeof(*env));