diff --git a/files/aclchecker.py b/files/aclchecker.py new file mode 100644 index 0000000..db3b0b0 --- /dev/null +++ b/files/aclchecker.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + (c) 2014-2018 - Copyright Red Hat Inc + + Authors: + Patrick Uiterwijk + +""" + +from __future__ import unicode_literals, print_function + +import subprocess +import sys +import os + +# Since this is run by sshd, we don't have a way to set environment +# variables ahead of time +if "PAGURE_CONFIG" not in os.environ and os.path.exists( + "/etc/pagure/pagure.cfg" +): + os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg" + +# Here starts the code +import pagure +import pagure.lib +from pagure.utils import is_repo_user +from pagure.config import config as pagure_config + + +# Get the arguments +if len(sys.argv) != 2: + print("Invalid call, too few arguments", file=sys.stderr) + sys.exit(1) +remoteuser = sys.argv[1] + +args = os.environ["SSH_ORIGINAL_COMMAND"].split(" ") +# Expects: +if len(args) != 2: + print("Invalid call, too few inner arguments", file=sys.stderr) + sys.exit(1) + + +cmd = args[0] +path = args[1] +if cmd not in ("git-receive-pack", "git-upload-pack"): + print("Invalid call, invalid operation", file=sys.stderr) + sys.exit(1) + +# Git will encode the file path argument within single quotes +if path[0] != "'" or path[-1] != "'": + print("Invalid call: invalid path", file=sys.stderr) + sys.exit(1) +path = path[1:-1] + +if os.path.isabs(path): + print("Non-full path expected, not %s" % path, file=sys.stderr) + sys.exit(1) + +if not path.endswith(".git"): + path = path + ".git" + +session = pagure.lib.create_session(pagure_config["DB_URL"]) +if not session: + raise Exception("Unable to initialize db session") + +gitdir = os.path.join(pagure_config["GIT_FOLDER"], path) +(repotype, username, namespace, repo) = pagure.lib.git.get_repo_info_from_path( + gitdir, hide_notfound=True +) + +if repo is None: + print("Repo not found", file=sys.stderr) + sys.exit(1) + +project = pagure.lib.get_authorized_project( + session, repo, user=username, namespace=namespace, asuser=remoteuser +) + +if not project: + print("Repo not found", file=sys.stderr) + sys.exit(1) + +if repotype != "main" and not is_repo_user(project, remoteuser): + print("Repo not found", file=sys.stderr) + sys.exit(1) + +# Now go run git +# We verified that cmd is either "git-receive-pack" or "git-send-pack" +# and "gitdir" is a full, absolute, path within GIT_FOLDER that points to +# the canonical location for this git repo. +os.execvp(cmd, [cmd, gitdir]) diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 89a27f4..2a9bd61 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -5435,7 +5435,7 @@ def issues_history_stats(session, project): return output -def get_authorized_project(session, project_name, user=None, namespace=None): +def get_authorized_project(session, project_name, user=None, namespace=None, asuser=None): """ Retrieving the project with user permission constraint :arg session: The SQLAlchemy session to use @@ -5446,6 +5446,8 @@ def get_authorized_project(session, project_name, user=None, namespace=None): :type user: String :arg namespace: Pagure namespace :type namespace: String + :arg asuser: Username to check for access + :type asuser: String :return: The project object if project is public or user has permissions for the project else it returns None :rtype: Project @@ -5453,7 +5455,7 @@ def get_authorized_project(session, project_name, user=None, namespace=None): """ repo = pagure.lib._get_project(session, project_name, user, namespace) - if repo and repo.private and not pagure.utils.is_repo_user(repo): + if repo and repo.private and not pagure.utils.is_repo_user(repo, asuser): return None return repo diff --git a/pagure/lib/git.py b/pagure/lib/git.py index e9ac914..08b3f80 100644 --- a/pagure/lib/git.py +++ b/pagure/lib/git.py @@ -1261,7 +1261,7 @@ def get_commit_subject(commit, abspath): return subject -def get_repo_info_from_path(gitdir): +def get_repo_info_from_path(gitdir, hide_notfound=False): """ Returns the name, username, namespace and type of a git directory This gets computed based on the *_FOLDER's in the config file, @@ -1269,6 +1269,10 @@ def get_repo_info_from_path(gitdir): Args: gitdir (string): Path of the canonical git repository + hide_notfound (bool): Whether to return a tuple with None's instead of + raising an error if the regenerated repo didn't exist. + Can be used to hide the difference between no project access vs not + existing when looking up private repos. Return: (tuple): Tuple with (repotype, username, namespace, repo) Some of these elements may be None if not applicable. """ @@ -1356,7 +1360,10 @@ def get_repo_info_from_path(gitdir): % (rebuiltpath, gitdir) ) if not os.path.exists(rebuiltpath): - raise ValueError("Splitting gitdir %s failed" % gitdir) + if hide_notfound: + return (None, None, None, None) + else: + raise ValueError("Splitting gitdir %s failed" % gitdir) return (repotype, username, namespace, repo) diff --git a/pagure/utils.py b/pagure/utils.py index 25165ca..0ab261d 100644 --- a/pagure/utils.py +++ b/pagure/utils.py @@ -161,12 +161,11 @@ def is_repo_committer(repo_obj, username=None): def is_repo_user(repo_obj, username=None): """ Return whether the user has some access in the provided repo. """ - if not authenticated(): - return False - if username: user = username else: + if not authenticated(): + return False user = flask.g.fas_user.username if is_admin():