commit f3807fe5829048c18652abf3e9c2b5f0bb3d0599 from: Stefan Sperling via: Thomas Adam date: Mon Jul 10 19:47:10 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 - fdbea373595afc1c293f4ebbe17b0b07a6cc904d commit + f3807fe5829048c18652abf3e9c2b5f0bb3d0599 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 - f096baf28be2970ac75987af00fbdf3834130ea1 blob + 0571f1950975143bcb4345465892fc7545221c44 --- gotd/gotd.c +++ gotd/gotd.c @@ -726,7 +726,8 @@ static const char *gotd_proc_names[PROC_MAX] = { "session_read", "session_write", "repo_read", - "repo_write" + "repo_write", + "gitwrapper" }; static void @@ -1855,7 +1856,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));