commit - da9a9ea87f65f3809ff8edf4fb6314c1a6dd95aa
commit + ff260661299dea92ad32c7d92d4e206bac21fb1b
blob - b8b141d19d580a01c1cc68f758b798a5f2947b11
blob + 635359fa3bec3e806959e35bd5e383ffdbdd2ec8
--- gotd/auth.c
+++ gotd/auth.c
#include <errno.h>
#include <event.h>
+#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <imsg.h>
+#include <unistd.h>
#include "got_error.h"
#include "gotd.h"
+#include "log.h"
#include "auth.h"
static int
gid_t rgid;
if (parsegid(identifier + 1, &rgid) == -1)
return 0;
+ if (rgid == egid)
+ return 1;
for (i = 0; i < ngroups; i++) {
- if (rgid == groups[i] && egid == rgid)
+ if (rgid == groups[i])
break;
}
if (i == ngroups)
const struct got_error *
gotd_auth_check(struct gotd_access_rule_list *rules, const char *repo_name,
- gid_t *groups, int ngroups, uid_t euid, gid_t egid,
- int required_auth)
+ uid_t euid, gid_t egid, int required_auth)
{
struct gotd_access_rule *rule;
enum gotd_access access = GOTD_ACCESS_DENIED;
+ struct passwd *pw;
+ gid_t groups[NGROUPS_MAX];
+ int ngroups = NGROUPS_MAX;
+ pw = getpwuid(euid);
+ if (pw == NULL)
+ return got_error_from_errno("getpwuid");
+
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1)
+ log_warnx("group membership list truncated");
+
STAILQ_FOREACH(rule, rules, entry) {
if (!match_identifier(rule->identifier, groups, ngroups,
euid, egid))
blob - 480be955e04852bc1940c62233137deaeebcaedf
blob + 506f5e8b84ac2182f7114a5f4569b3b8d6963cc2
--- gotd/auth.h
+++ gotd/auth.h
const struct got_error *
gotd_auth_check(struct gotd_access_rule_list *rules, const char *repo_name,
- gid_t *groups, int ngroups, uid_t euid, gid_t egid, int required_auth);
+ uid_t euid, gid_t egid, int required_auth);
blob - 884188a6d45969d44a774615f1c7aea23f5817cb
blob + 72048daec19573331134b6d17c9b798b8d34d7d6
--- gotd/gotd.c
+++ gotd/gotd.c
if (repo == NULL)
return got_error(GOT_ERR_NOT_GIT_REPO);
err = gotd_auth_check(&repo->rules, repo->name,
- gotd.groups, gotd.ngroups, client->euid, client->egid,
- GOTD_AUTH_READ);
+ client->euid, client->egid, GOTD_AUTH_READ);
if (err)
return err;
client->repo_read = find_proc_by_repo_name(PROC_REPO_READ,
repo = find_repo_by_name(ireq.repo_name);
if (repo == NULL)
return got_error(GOT_ERR_NOT_GIT_REPO);
- err = gotd_auth_check(&repo->rules, repo->name,
- gotd.groups, gotd.ngroups, client->euid, client->egid,
- GOTD_AUTH_READ | GOTD_AUTH_WRITE);
+ err = gotd_auth_check(&repo->rules, repo->name, client->euid,
+ client->egid, GOTD_AUTH_READ | GOTD_AUTH_WRITE);
if (err)
return err;
client->repo_write = find_proc_by_repo_name(PROC_REPO_WRITE,
const char *confpath = GOTD_CONF_PATH;
char *argv0 = argv[0];
char title[2048];
+ gid_t groups[NGROUPS_MAX];
int ngroups = NGROUPS_MAX;
struct passwd *pw = NULL;
struct group *gr = NULL;
getprogname(), pw->pw_name, getprogname());
}
- if (getgrouplist(pw->pw_name, pw->pw_gid, gotd.groups, &ngroups) == -1)
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1)
log_warnx("group membership list truncated");
- gotd.ngroups = ngroups;
- gr = match_group(gotd.groups, ngroups, gotd.unix_group_name);
+ gr = match_group(groups, ngroups, gotd.unix_group_name);
if (gr == NULL) {
fatalx("cannot start %s: the user running %s "
"must be a secondary member of group %s",
blob - fa1f5d66ce3b4c6691a931b445425921470634a2
blob + 1137c32a92e87b805d1195b4b06d153a9a53d1fa
--- gotd/gotd.h
+++ gotd/gotd.h
struct event pause;
struct gotd_child_proc *procs;
int nprocs;
- gid_t groups[NGROUPS_MAX];
- int ngroups;
};
enum gotd_imsg_type {
blob - 773e9c0dfd3c2e287025d41ffed9f3749b380941
blob + be6e907b0b228adb916c00a7d370b73d769dd8ed
--- regress/gotd/Makefile
+++ regress/gotd/Makefile
-REGRESS_TARGETS=test_repo_read test_repo_write test_repo_write_empty
+REGRESS_TARGETS=test_repo_read test_repo_read_group test_repo_read_bad_group \
+ test_repo_write test_repo_write_empty
NOOBJ=Yes
.PHONY: ensure_root prepare_test_repo check_test_repo start_gotd
@$(GOTD_TRAP); $(GOTD_START_CMD)
@$(GOTD_TRAP); sleep .5
+start_gotd_ro_group: ensure_root
+ @echo 'unix_socket "$(GOTD_SOCK)"' > $(PWD)/gotd.conf
+ @echo "unix_group $(GOTD_GROUP)" >> $(PWD)/gotd.conf
+ @echo "user $(GOTD_USER)" >> $(PWD)/gotd.conf
+ @echo 'repository "test-repo" {' >> $(PWD)/gotd.conf
+ @echo ' path "$(GOTD_TEST_REPO)"' >> $(PWD)/gotd.conf
+ @echo ' permit ro :$(GOTD_DEVUSER)' >> $(PWD)/gotd.conf
+ @echo "}" >> $(PWD)/gotd.conf
+ @$(GOTD_TRAP); $(GOTD_START_CMD)
+ @$(GOTD_TRAP); sleep .5
+
+# $GOTD_DEVUSER should not be in group wheel
+start_gotd_ro_bad_group: ensure_root
+ @echo 'unix_socket "$(GOTD_SOCK)"' > $(PWD)/gotd.conf
+ @echo "unix_group $(GOTD_GROUP)" >> $(PWD)/gotd.conf
+ @echo "user $(GOTD_USER)" >> $(PWD)/gotd.conf
+ @echo 'repository "test-repo" {' >> $(PWD)/gotd.conf
+ @echo ' path "$(GOTD_TEST_REPO)"' >> $(PWD)/gotd.conf
+ @echo ' permit ro :wheel' >> $(PWD)/gotd.conf
+ @echo "}" >> $(PWD)/gotd.conf
+ @$(GOTD_TRAP); $(GOTD_START_CMD)
+ @$(GOTD_TRAP); sleep .5
+
+
start_gotd_rw: ensure_root
@echo 'unix_socket "$(GOTD_SOCK)"' > $(PWD)/gotd.conf
@echo "unix_group $(GOTD_GROUP)" >> $(PWD)/gotd.conf
@$(GOTD_STOP_CMD) 2>/dev/null
@su -m ${GOTD_USER} -c 'env $(GOTD_TEST_ENV) sh ./check_test_repo.sh'
+test_repo_read_group: prepare_test_repo start_gotd_ro_group
+ @-$(GOTD_TRAP); su ${GOTD_TEST_USER} -c \
+ 'env $(GOTD_TEST_ENV) sh ./repo_read.sh'
+ @$(GOTD_STOP_CMD) 2>/dev/null
+ @su -m ${GOTD_USER} -c 'env $(GOTD_TEST_ENV) sh ./check_test_repo.sh'
+
+test_repo_read_bad_group: prepare_test_repo start_gotd_ro_bad_group
+ @-$(GOTD_TRAP); su ${GOTD_TEST_USER} -c \
+ 'env $(GOTD_TEST_ENV) sh ./repo_read_access_denied.sh'
+ @$(GOTD_STOP_CMD) 2>/dev/null
+ @su -m ${GOTD_USER} -c 'env $(GOTD_TEST_ENV) sh ./check_test_repo.sh'
+
test_repo_write: prepare_test_repo start_gotd_rw
@-$(GOTD_TRAP); su ${GOTD_TEST_USER} -c \
'env $(GOTD_TEST_ENV) sh ./repo_write.sh'
blob - /dev/null
blob + c8b4fc889c65a723539f0957fff96fda7cd7d32b (mode 644)
--- /dev/null
+++ regress/gotd/repo_read_access_denied.sh
+#!/bin/sh
+#
+# Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+. ../cmdline/common.sh
+. ./common.sh
+
+test_clone_basic_access_denied() {
+ local testroot=`test_init clone_basic_access_denied 1`
+
+ cp -r ${GOTD_TEST_REPO} $testroot/repo-copy
+
+ got clone -q ${GOTD_TEST_REPO_URL} $testroot/repo-clone \
+ 2> $testroot/stderr
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "got clone succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ # Verify that the clone operation failed.
+ echo 'got-fetch-pack: test-repo: Permission denied' \
+ > $testroot/stderr.expected
+ echo 'got: fetch failed' >> $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ fi
+ test_done "$testroot" "$ret"
+}
+
+test_parseargs "$@"
+run_test test_clone_basic_access_denied