commit - c343b6811380169034b3341781bac5f3a347e7f6
commit + 1d26dbd4b176e993c088a1b058223d613ef9365c
blob - 8628a270bcaa8929d1e004abd3806a8d7a407f26
blob + 59f265132b4c3bb5c9a65a0446dcdab1fd40b67d
--- gotsysd/gotsysd.c
+++ gotsysd/gotsysd.c
if (gotsysd.db_commit_fd != -1)
close(gotsysd.db_commit_fd);
+
+ free(gotsysd.global_repo_access_rules);
log_info("terminating");
exit(0);
#endif
apply_unveil_none();
- sysconf_main(title, gotsysd.uid_start, gotsysd.uid_end);
+ sysconf_main(title, gotsysd.uid_start, gotsysd.uid_end,
+ gotsysd.global_repo_access_rules);
/* NOTREACHED */
break;
default:
blob - f20dbdab9b039423e97af70ac7b8e753ea7b842d
blob + 9ff79bd55e851c72c79fb7789521958b3eb86210
--- gotsysd/gotsysd.conf.5
+++ gotsysd/gotsysd.conf.5
If not specified, the path
.Pa /git
will be used.
+.It Ic repository Ic deny Ar identity
+Deny repository access to users with the username
+.Ar identity .
+.Pp
+Access rules set in
+.Nm
+apply to all repositories and override conflicting per-repository access
+rules specified in
+.Xr gotsys.conf 5 .
+.Pp
+Group names may be matched by prepending a colon
+.Pq Sq \&:
+to
+.Ar identity .
+.Pp
+The special user
+.Ar identity
+.Dq *
+(an asterisk) can be used to match all users, including the
+.Dq anonymous
+user.
+.Pp
+Multiple access rules can be specified, and the last matching rule
+determines the action taken.
+If no rule matches, the per-repository rules specified in
+.Xr gotsys.conf 5
+will take effect.
+.It Ic repository Ic permit Ar mode Ar identity
+Permit repository access to users with the username
+.Ar identity .
+.Pp
+Access rules set in
+.Nm
+apply to all repositories and override conflicting per-repository access
+rules specified in
+.Xr gotsys.conf 5 .
+.Pp
+The
+.Ar mode
+argument must be set to either
+.Ic ro
+for read-only access,
+or
+.Ic rw
+for read-write access.
+Group names may be matched by prepending a colon
+.Pq Sq \&:
+to
+.Ar identity .
+.Pp
+The special user
+.Ar identity
+.Dq anonymous
+can be used when public read-only access to repositories over SSH is desired.
+The anonymous user has an empty password, cannot use an SSH public key, and
+can only be granted read-only access.
+.Pp
+The special user
+.Ar identity
+.Dq *
+(an asterisk) can be used to match all users, except the
+.Dq anonymous
+user.
+Read-only anonymous access must be enabled explicitly.
+.Pp
+Multiple access rules can be specified, and the last matching rule
+determines the action taken.
+If no rule matches, the per-repository rules specified in
+.Xr gotsys.conf 5
+will take effect.
.It Ic uid range Ar start Ar end
Set the start and end (inclusive) of the range from which
.Xr gotsysd 8
repository directory "/git"
uid range 5000 5999
.Ed
+.Pp
+Regardless of what
+.Xr gotsys.conf 5
+says, allow the user account
+.Dq backup-user
+to read any repository:
+.Bd -literal -offset indent
+repository permit ro backup-user
+.Ed
+.Pp
+Regardless of what
+.Xr gotsys.conf 5
+says, make all repositories read-only:
+.Bd -literal -offset indent
+repository permit ro "*"
+.Ed
+.Pp
+Regardless of what
+.Xr gotsys.conf 5
+says, make all repositories inaccessible:
+.Bd -literal -offset indent
+repository deny "*"
+.Ed
.Sh SEE ALSO
.Xr got 1 ,
.Xr gotd 8 ,
blob - f72e5f0ff065e99ca9f7e168dbd69ae18ba02940
blob + b6a2d93351ce9620926282a1ad82b34e21529cc6
--- gotsysd/gotsysd.h
+++ gotsysd/gotsysd.h
int sysconf_fd;
char *sysconf_commit_id_str;
struct gotsysd_access_rule_list access_rules;
+ struct gotsys_access_rule_list *global_repo_access_rules;
struct event sysconf_tmo;
struct gotsysd_pending_sysconf_cmd_list sysconf_pending;
GOTSYSD_IMSG_SYSCONF_AUTHORIZED_KEYS_DONE,
GOTSYSD_IMSG_SYSCONF_REPO,
GOTSYSD_IMSG_SYSCONF_REPOS_DONE,
+ GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULE,
+ GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULES_DONE,
GOTSYSD_IMSG_SYSCONF_ACCESS_RULE,
GOTSYSD_IMSG_SYSCONF_ACCESS_RULES_DONE,
GOTSYSD_IMSG_SYSCONF_PROTECTED_TAG_NAMESPACES,
struct imsg *);
const struct got_error *gotsys_imsg_recv_authorized_keys(struct imsg *,
struct gotsys_authorized_keys_list *);
+const struct got_error *gotsys_imsg_send_access_rule(struct gotsysd_imsgev *,
+ struct gotsys_access_rule *, int);
const struct got_error *gotsys_imsg_send_repositories(struct gotsysd_imsgev *,
struct gotsys_repolist *);
const struct got_error *gotsys_imsg_recv_repository(struct gotsys_repo **,
blob - a9f801243fe0f3232af577fb8cdcfc0cadbb2442
blob + 7e3a2d02aa64a6ad196c47fb3ce747ed6294522b
--- gotsysd/helpers.c
+++ gotsysd/helpers.c
case GOTSYSD_IMSG_SYSCONF_WRITE_CONF_GROUP_MEMBERS_DONE:
case GOTSYSD_IMSG_SYSCONF_WRITE_CONF_GROUPS_DONE:
case GOTSYSD_IMSG_SYSCONF_REPO:
+ case GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULE:
+ case GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULES_DONE:
case GOTSYSD_IMSG_SYSCONF_ACCESS_RULE:
case GOTSYSD_IMSG_SYSCONF_ACCESS_RULES_DONE:
case GOTSYSD_IMSG_SYSCONF_PROTECTED_TAG_NAMESPACES:
blob - be28e070e622a6bb2ad28de4120884dfffc27dfc
blob + 7996125cee248ac4fb8218d775a7a8b6a3f47ddf
--- gotsysd/libexec/gotsys-write-conf/gotsys-write-conf.c
+++ gotsysd/libexec/gotsys-write-conf/gotsys-write-conf.c
static size_t nprotected_refs_received;
static int gotd_conf_tmpfd = -1;
static char *gotd_conf_tmppath;
+static struct gotsys_access_rule_list global_repo_access_rules;
enum writeconf_state {
WRITECONF_STATE_EXPECT_USERS,
}
static const struct got_error *
+write_access_rule(const char *access, const char * authorization,
+ const char *identifier)
+{
+ int ret;
+
+ ret = dprintf(gotd_conf_tmpfd, "\t%s%s%s\n",
+ access, authorization, identifier);
+ if (ret == -1)
+ return got_error_from_errno2("dprintf", gotd_conf_tmppath);
+ if (ret != 1 + strlen(access) + strlen(authorization) +
+ strlen(identifier) + 1) {
+ return got_error_fmt(GOT_ERR_IO,
+ "short write to %s", gotd_conf_tmppath);
+ }
+
+ return NULL;
+}
+
+static const struct got_error *
+write_global_access_rules(void)
+{
+ const struct got_error *err;
+ struct gotsys_access_rule *rule;
+
+ STAILQ_FOREACH(rule, &global_repo_access_rules, entry) {
+ const char *access, *authorization;
+
+ switch (rule->access) {
+ case GOTSYS_ACCESS_DENIED:
+ access = "deny ";
+ break;
+ case GOTSYS_ACCESS_PERMITTED:
+ access = "permit ";
+ break;
+ default:
+ return got_error_fmt(GOT_ERR_PARSE_CONFIG,
+ "access rule with unknown access flag %d",
+ rule->access);
+ }
+
+ if (rule->authorization & GOTSYS_AUTH_WRITE)
+ authorization = "rw ";
+ else if (rule->authorization & GOTSYS_AUTH_READ)
+ authorization = "ro ";
+ else
+ authorization = "";
+
+ if (strcmp(rule->identifier, "*") == 0) {
+ struct gotsys_user *user;
+
+ STAILQ_FOREACH(user, &gotsysconf.users, entry) {
+ /*
+ * Anonymous read access must be enabled
+ * explicitly, not via *.
+ */
+ if (rule->access == GOTSYS_ACCESS_PERMITTED &&
+ strcmp(user->name, "anonymous") == 0)
+ continue;
+ err = write_access_rule(access, authorization,
+ user->name);
+ if (err)
+ return err;
+ }
+ } else {
+ err = write_access_rule(access, authorization,
+ rule->identifier);
+ if (err)
+ return err;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct got_error *
write_access_rules(struct gotsys_access_rule_list *rules)
{
+ const struct got_error *err;
struct gotsys_access_rule *rule;
STAILQ_FOREACH(rule, rules, entry) {
const char *access, *authorization;
- int ret;
switch (rule->access) {
case GOTSYS_ACCESS_DENIED:
else
authorization = "";
- ret = dprintf(gotd_conf_tmpfd, "\t%s%s%s\n",
- access, authorization, rule->identifier);
- if (ret == -1)
- return got_error_from_errno2("dprintf",
- gotd_conf_tmppath);
- if (ret != 1 + strlen(access) + strlen(authorization) +
- strlen(rule->identifier) + 1) {
- return got_error_fmt(GOT_ERR_IO,
- "short write to %s", gotd_conf_tmppath);
- }
+ err = write_access_rule(access, authorization,
+ rule->identifier);
+ if (err)
+ return err;
}
return NULL;
if (err)
return err;
+ err = write_global_access_rules();
+ if (err)
+ return err;
+
err = write_protected_refs(repo);
if (err)
return err;
break;
TAILQ_INSERT_TAIL(&gotsysconf.repos, repo, entry);
repo_cur = repo;
+ break;
+ }
+ case GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULE: {
+ struct gotsys_access_rule *rule;
+ if (writeconf_state != WRITECONF_STATE_EXPECT_REPOS) {
+ err = got_error_fmt(GOT_ERR_PRIVSEP_MSG,
+ "received unexpected imsg %d while in "
+ "state %d\n", imsg.hdr.type,
+ writeconf_state);
+ break;
+ }
+ err = gotsys_imsg_recv_access_rule(&rule, &imsg,
+ NULL, NULL);
+ if (err)
+ break;
+ STAILQ_INSERT_TAIL(&global_repo_access_rules, rule,
+ entry);
break;
}
+ case GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULES_DONE:
+ if (writeconf_state != WRITECONF_STATE_EXPECT_REPOS) {
+ err = got_error_fmt(GOT_ERR_PRIVSEP_MSG,
+ "received unexpected imsg %d while in "
+ "state %d\n", imsg.hdr.type,
+ writeconf_state);
+ break;
+ }
+ break;
case GOTSYSD_IMSG_SYSCONF_ACCESS_RULE: {
struct gotsys_access_rule_list *rules;
struct gotsys_access_rule *rule;
while (!attached)
sleep(1);
#endif
+ STAILQ_INIT(&global_repo_access_rules);
gotsys_conf_init(&gotsysconf);
event_init();
blob - 5382a6cf8d17e10cec59c8629b221a1dbf6cf6d2
blob + 845732b3050151e7063b1800afbf3857993212b6
--- gotsysd/parse.y
+++ gotsysd/parse.y
#include "log.h"
#include "gotsysd.h"
+#include "gotsys.h"
#ifndef GOTD_USER
#define GOTD_USER "_gotd"
static enum gotsysd_procid gotsysd_proc_id;
static void conf_new_access_rule(enum gotsysd_access, char *);
+static const struct got_error *conf_new_repo_access_rule(enum gotsys_access,
+ int, const char *);
typedef struct {
union {
%}
%token ERROR LISTEN ON USER GOTD DIRECTORY REPOSITORY UID RANGE PERMIT
+%token DENY RO RW
%token <v.string> STRING
%token <v.number> NUMBER
$2);
} else
free($2);
+ }
+ | REPOSITORY DENY numberstring {
+ const struct got_error *err;
+
+ err = conf_new_repo_access_rule(GOTSYS_ACCESS_DENIED,
+ 0, $3);
+ if (err) {
+ yyerror("%s", err->msg);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | REPOSITORY PERMIT RO numberstring {
+ const struct got_error *err;
+
+ err = conf_new_repo_access_rule(GOTSYS_ACCESS_PERMITTED,
+ GOTSYS_AUTH_READ, $4);
+ if (err) {
+ yyerror("%s", err->msg);
+ free($4);
+ YYERROR;
+ }
+ free($4);
}
+ | REPOSITORY PERMIT RW numberstring {
+ const struct got_error *err;
+
+ err = conf_new_repo_access_rule(GOTSYS_ACCESS_PERMITTED,
+ GOTSYS_AUTH_READ | GOTSYS_AUTH_WRITE, $4);
+ if (err) {
+ yyerror("%s", err->msg);
+ free($4);
+ YYERROR;
+ }
+ free($4);
+ }
;
%%
{
/* This has to be sorted always. */
static const struct keywords keywords[] = {
+ { "deny", DENY },
{ "directory", DIRECTORY },
{ "gotd", GOTD },
{ "listen", LISTEN },
{ "permit", PERMIT },
{ "range", RANGE },
{ "repository", REPOSITORY },
+ { "ro", RO },
+ { "rw", RW },
{ "uid", UID },
{ "user", USER },
};
{
struct sym *sym, *next;
int require_config_file = 0;
+ struct gotsys_access_rule_list *global_repo_access_rules;
memset(pgotsysd, 0, sizeof(*pgotsysd));
gotsysd_proc_id = proc_id;
STAILQ_INIT(&gotsysd->access_rules);
+
+ global_repo_access_rules = malloc(sizeof(*global_repo_access_rules));
+ if (global_repo_access_rules == NULL) {
+ fprintf(stderr, "%s: malloc: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+ gotsysd->global_repo_access_rules = global_repo_access_rules;
+ STAILQ_INIT(gotsysd->global_repo_access_rules);
+ global_repo_access_rules = NULL;
/* Apply default values. */
if (strlcpy(gotsysd->unix_socket_path, GOTSYSD_UNIX_SOCKET,
STAILQ_INSERT_TAIL(&gotsysd->access_rules, rule, entry);
}
+
+static const struct got_error *
+conf_new_repo_access_rule(enum gotsys_access access, int authorization,
+ const char *identifier)
+{
+ const struct got_error *err;
+ struct gotsys_access_rule *rule;
+ const char *name = identifier;
+
+ if (strcmp(name, "*") != 0) {
+ if (name[0] == ':') {
+ name++;
+ err = gotsys_conf_validate_name(name, "group");
+ if (err)
+ return err;
+ } else {
+ err = gotsys_conf_validate_name(name, "user");
+ if (err)
+ return err;
+ }
+ }
+
+ err = gotsys_conf_new_access_rule(&rule, access, authorization,
+ identifier, NULL, NULL);
+ if (err)
+ return err;
+
+ STAILQ_INSERT_TAIL(gotsysd->global_repo_access_rules, rule, entry);
+ return NULL;
+}
blob - e3f8794ab608fefd10b1564764fb55cb242295fa
blob + 7fee8a40df4446794f8d3b8d9b88ebcfe89559f4
--- gotsysd/sysconf.c
+++ gotsysd/sysconf.c
size_t *nprotected_refs_cur;
size_t nprotected_refs_needed;
size_t nprotected_refs_received;
+ struct gotsys_access_rule_list *global_repo_access_rules;
} gotsysd_sysconf;
static struct gotsys_conf gotsysconf;
send_gotsysconf(struct gotsysd_imsgev *iev)
{
const struct got_error *err;
+ struct gotsys_access_rule *rule;
err = gotsys_imsg_send_users(iev, &gotsysconf.users,
GOTSYSD_IMSG_SYSCONF_WRITE_CONF_USERS,
GOTSYSD_IMSG_SYSCONF_WRITE_CONF_GROUPS_DONE);
if (err)
return err;
+
+ STAILQ_FOREACH(rule, gotsysd_sysconf.global_repo_access_rules, entry) {
+ err = gotsys_imsg_send_access_rule(iev, rule,
+ GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULE);
+ if (err)
+ return err;
+ }
+
+ if (gotsysd_imsg_compose_event(iev,
+ GOTSYSD_IMSG_SYSCONF_GLOBAL_ACCESS_RULES_DONE, 0, -1,
+ NULL, 0) == -1)
+ return got_error_from_errno("gotsysd_imsg_compose_event");
err = gotsys_imsg_send_repositories(iev, &gotsysconf.repos);
if (err)
}
void
-sysconf_main(const char *title, uid_t uid_start, uid_t uid_end)
+sysconf_main(const char *title, uid_t uid_start, uid_t uid_end,
+ struct gotsys_access_rule_list *global_repo_access_rules)
{
struct event evsigint, evsigterm, evsighup, evsigusr1;
struct gotsysd_imsgev *iev = &gotsysd_sysconf.parent_iev;
gotsysd_sysconf.state = SYSCONF_STATE_EXPECT_PARSING_SUCCESS;
gotsysd_sysconf.uid_start = uid_start;
gotsysd_sysconf.uid_end = uid_end;
+ gotsysd_sysconf.global_repo_access_rules = global_repo_access_rules;
signal_set(&evsigint, SIGINT, sysconf_sighdlr, NULL);
signal_set(&evsigterm, SIGTERM, sysconf_sighdlr, NULL);
blob - 69dabe3a4134e1f341dc15b645eb8fbd6f495b93
blob + 8391a0256347fa9315b8a27c887e89719ade65f5
--- gotsysd/sysconf.h
+++ gotsysd/sysconf.h
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-void sysconf_main(const char *, uid_t, uid_t);
+void sysconf_main(const char *, uid_t, uid_t, struct gotsys_access_rule_list *);
blob - fa11004e9e14a9712ef0b3c3ea8e2c4dfc98123a
blob + 05fad5e984044a6e291365ac1358ec288a6da1c0
--- lib/gotsys_conf.c
+++ lib/gotsys_conf.c
return got_error_fmt(GOT_ERR_PARSE_CONFIG,
"empty group name in access rule");
- STAILQ_FOREACH(group, groups, entry) {
- if (strcmp(group->name, name) == 0)
- break;
- }
- if (group == NULL) {
- return got_error_fmt(GOT_ERR_PARSE_CONFIG,
- "reference to undeclared group '%s' via "
- "access rule", name);
+ if (groups) {
+ STAILQ_FOREACH(group, groups, entry) {
+ if (strcmp(group->name, name) == 0)
+ break;
+ }
+ if (group == NULL) {
+ return got_error_fmt(GOT_ERR_PARSE_CONFIG,
+ "reference to undeclared group '%s' via "
+ "access rule", name);
+ }
}
} else if (strcmp(name, "anonymous") == 0) {
if (access == GOTSYS_ACCESS_PERMITTED &&
"the \"anonymous\" user must not have write "
"permission");
}
- } else {
+ } else if (users) {
struct gotsys_user *user = NULL;
STAILQ_FOREACH(user, users, entry) {
blob - 7d5a4aa34f40e6f7de34db562bf6b6c32e22df98
blob + be6c5e0e7bf717619f74605bb70de1188f08480e
--- lib/gotsys_imsg.c
+++ lib/gotsys_imsg.c
return err;
}
-static const struct got_error *
-send_access_rule(struct gotsysd_imsgev *iev,
- struct gotsys_access_rule *rule)
+const struct got_error *
+gotsys_imsg_send_access_rule(struct gotsysd_imsgev *iev,
+ struct gotsys_access_rule *rule, int imsg_type)
{
struct gotsysd_imsg_sysconf_access_rule irule;
struct ibuf *wbuf = NULL;
irule.authorization = rule->authorization;
irule.identifier_len = strlen(rule->identifier);
- wbuf = imsg_create(&iev->ibuf, GOTSYSD_IMSG_SYSCONF_ACCESS_RULE,
+ wbuf = imsg_create(&iev->ibuf, imsg_type,
0, 0, sizeof(irule) + irule.identifier_len);
if (wbuf == NULL)
return got_error_from_errno("imsg_create SYSCONF_ACCESS_RULE");
imsg_close(&iev->ibuf, wbuf);
STAILQ_FOREACH(rule, &repo->access_rules, entry) {
- err = send_access_rule(iev, rule);
+ err = gotsys_imsg_send_access_rule(iev, rule,
+ GOTSYSD_IMSG_SYSCONF_ACCESS_RULE);
if (err)
return err;
}
blob - 7e60f16b3db43adbee999e9d75a456e2c5327ea1
blob + cd4dfe61444049bb6012ccddeb973b174dbe2083
--- regress/gotsysd/test_gotsysd.sh
+++ regress/gotsysd/test_gotsysd.sh
fi
echo "gotsh: foo: Permission denied" > $testroot/stderr.expected
+ grep '^gotsh:' $testroot/stderr > $testroot/stderr.filtered
+ cmp -s $testroot/stderr.expected $testroot/stderr.filtered
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr.filtered
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
+test_override_access_rules() {
+ local testroot=`test_init override_access_rules 1`
+
+ # Override gotsys.conf access rules which deny access to foo.git.
+ echo "repository permit ro ${GOTSYSD_DEV_USER}" | \
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
+ 'cat >> /etc/gotsysd.conf'
+
+ # Restart gotsysd (XXX need a better way to do this...)
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'pkill -xf /usr/local/sbin/gotsysd'
+ sleep 1
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} '/usr/local/sbin/gotsysd -vvv'
+ sleep 1
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'gotsys apply -w' > /dev/null
+
+ # Cloning repository foo should now succeed.
+ got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \
+ ${GOTSYSD_DEV_USER}@${VMIP}:foo.git $testroot/foo.git \
+ > $testroot/stdout 2> $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got clone failed unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+
+ # gotsys.git access should now be read-only.
+ got clone -q -i ${GOTSYSD_SSH_KEY} \
+ ${GOTSYSD_DEV_USER}@${VMIP}:gotsys.git $testroot/gotsys2.git \
+ > $testroot/stdout 2> $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got clone failed unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+ got checkout -q $testroot/gotsys2.git $testroot/wt >/dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got checkout failed unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+
+ crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
+ crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
+ sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
+ cat > ${testroot}/wt/gotsys.conf <<EOF
+group slackers
+
+user ${GOTSYSD_TEST_USER} {
+ password "${crypted_vm_pw}"
+ authorized key ${sshkey}
+}
+user ${GOTSYSD_DEV_USER} {
+ password "${crypted_pw}"
+ authorized key ${sshkey}
+}
+repository gotsys.git {
+ permit rw ${GOTSYSD_TEST_USER}
+ permit rw ${GOTSYSD_DEV_USER}
+}
+repository "foo" {
+ deny ${GOTSYSD_DEV_USER}
+ permit ro anonymous
+ head foo
+ protect branch foo
+ protect {
+ tag namespace "refs/tags"
+ }
+}
+repository "bar" {
+ permit rw ${GOTSYSD_DEV_USER}
+}
+EOF
+ (cd ${testroot}/wt && \
+ got commit -m "add bar.git repository" >/dev/null)
+ local commit_id=`git_show_head $testroot/gotsys2.git`
+
+ got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/gotsys2.git \
+ > $testroot/stdout 2> $testroot/stderr
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "got send succeeded unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+
+ echo "gotsh: gotsys.git: Permission denied" > $testroot/stderr.expected
grep '^gotsh:' $testroot/stderr > $testroot/stderr.filtered
cmp -s $testroot/stderr.expected $testroot/stderr.filtered
ret=$?
test_done "$testroot" "$ret"
return 1
fi
+ test_done "$testroot" "$ret"
+}
+test_override_all_user_access() {
+ local testroot=`test_init override_all_user_access 1`
+
+ # Override gotsys.conf access rules which deny access to foo.git.
+ echo 'repository deny "*"' | \
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
+ 'cat >> /etc/gotsysd.conf'
+
+ # Restart gotsysd (XXX need a better way to do this...)
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'pkill -xf /usr/local/sbin/gotsysd'
+ sleep 1
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} '/usr/local/sbin/gotsysd -vvv'
+ sleep 1
+ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'gotsys apply -w' > /dev/null
+
+ # Cloning any repository as any user should now fail.
+ for user in ${GOTSYSD_TEST_USER} ${GOTSYSD_DEV_USER} anonymous; do
+ got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \
+ ${user}@${VMIP}:foo.git $testroot/foo-${user}.git \
+ > $testroot/stdout 2> $testroot/stderr
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "got clone succeeded unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+
+ echo "got-fetch-pack: foo: Permission denied" \
+ > $testroot/stderr.expected
+ grep '^got-fetch-pack:' $testroot/stderr \
+ > $testroot/stderr.filtered
+ cmp -s $testroot/stderr.expected $testroot/stderr.filtered
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stderr.expected \
+ $testroot/stderr.filtered
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got clone -q -i ${GOTSYSD_SSH_KEY} \
+ ${user}@${VMIP}:gotsys.git \
+ $testroot/gotsys-${user}.git \
+ > $testroot/stdout 2> $testroot/stderr
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "got clone succeeded unexpectedly" >&2
+ test_done "$testroot" 1
+ return 1
+ fi
+
+ echo "got-fetch-pack: gotsys.git: Permission denied" \
+ > $testroot/stderr.expected
+ grep '^got-fetch-pack:' $testroot/stderr \
+ > $testroot/stderr.filtered
+ cmp -s $testroot/stderr.expected $testroot/stderr.filtered
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stderr.expected \
+ $testroot/stderr.filtered
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+ done
+
test_done "$testroot" "$ret"
}
run_test test_set_head
run_test test_protect_refs
run_test test_deny_access
+run_test test_override_access_rules
+run_test test_override_all_user_access