commit 9c574a767ec39853cd7c624009e002b8e40030a7 from: Stefan Sperling date: Mon May 06 17:41:34 2024 UTC don't leak the existence of gotd repositories to unrelated user accounts In particular, this prevents anonymous user accounts from discovering the existence of other private repositories served by gotd by correctly guessing the name of a private repository. They still wouldn't have read or write access but in some cases even knowledge about the existence of a particular repository could be cause for concern. ok op@ commit - d59a1c3b458751abda83fa864629003ee9b6ddad commit + 9c574a767ec39853cd7c624009e002b8e40030a7 blob - 46bcfeef428d4ba1125f8851a58966b8bf62c96d blob + 66b5696fc0fe4bca89de497a5be81b41c9d65b52 --- gotd/auth.c +++ gotd/auth.c @@ -136,6 +136,7 @@ auth_check(char **username, struct gotd_access_rule_li struct passwd *pw; gid_t groups[NGROUPS_MAX]; int ngroups = NGROUPS_MAX; + int matched_user = 0; *username = NULL; @@ -159,14 +160,23 @@ auth_check(char **username, struct gotd_access_rule_li euid, egid)) continue; + matched_user = 1; access = rule->access; if (rule->access == GOTD_ACCESS_PERMITTED && (rule->authorization & required_auth) != required_auth) access = GOTD_ACCESS_DENIED; } - if (access == GOTD_ACCESS_DENIED) - return got_error_set_errno(EACCES, repo_name); + if (access == GOTD_ACCESS_DENIED) { + /* + * If a user has no explicit read or write access then + * do not leak the existence of a repository to them. + */ + if (!matched_user) + return got_error(GOT_ERR_NOT_GIT_REPO); + else + return got_error_set_errno(EACCES, repo_name); + } if (access == GOTD_ACCESS_PERMITTED) return NULL; blob - cb2a4fed7b7467995301b65285bcdb7dbaac38ad blob + d210ed777ad16244f17aecd012723366f8862c8c --- regress/gotd/Makefile +++ regress/gotd/Makefile @@ -55,6 +55,7 @@ GOTD_TEST_ENV=GOTD_TEST_ROOT=$(GOTD_TEST_ROOT) \ GOTD_SOCK=$(GOTD_SOCK) \ GOTD_DEVUSER=$(GOTD_DEVUSER) \ GOTD_USER=$(GOTD_USER) \ + GOTD_CONF=$(PWD)/gotd.conf \ GOTD_TEST_SMTP_PORT=$(GOTD_TEST_SMTP_PORT) \ GOTD_TEST_HTTP_PORT=$(GOTD_TEST_HTTP_PORT) \ HOME=$(GOTD_TEST_USER_HOME) \ blob - f1eaa263ded2de0987d31ec852c1c021a68df9cc blob + 734479f1d4bb418a9468c905aed529752d696062 --- regress/gotd/repo_read_access_denied.sh +++ regress/gotd/repo_read_access_denied.sh @@ -33,8 +33,15 @@ test_clone_basic_access_denied() { grep ^got-fetch-pack: $testroot/stderr.raw > $testroot/stderr # Verify that the clone operation failed. - echo 'got-fetch-pack: test-repo: Permission denied' \ - > $testroot/stderr.expected + # The error returned will differ depending on whether read access + # is denied explicitly for GOTD_DEVUSER. + if grep -q "permit.*${GOTD_DEVUSER}$" $GOTD_CONF; then + echo 'got-fetch-pack: test-repo: Permission denied' \ + > $testroot/stderr.expected + else + echo 'got-fetch-pack: no git repository found' \ + > $testroot/stderr.expected + fi cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then blob - 9bfba2cfd281497c7e9b811178f4b534d191cc7e blob + c8b3337da837dcd5501b30cd8f9fc57f52366777 --- regress/gotd/repo_write_readonly.sh +++ regress/gotd/repo_write_readonly.sh @@ -58,8 +58,16 @@ EOF return 1 fi - echo "got-send-pack: test-repo: Permission denied" \ - > $testroot/stderr.expected + # Verify that the send operation failed. + # The error returned will differ depending on whether read access + # is denied explicitly for GOTD_DEVUSER. + if grep -q "permit.*${GOTD_DEVUSER}$" $GOTD_CONF; then + echo "got-send-pack: test-repo: Permission denied" \ + > $testroot/stderr.expected + else + echo 'got-send-pack: no git repository found' \ + > $testroot/stderr.expected + fi grep '^got-send-pack:' $testroot/stderr > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$?