From: Michal Novotny <minovotn@redhat.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Shawn Pearce <spearce@spearce.org>, git@vger.kernel.org
Subject: Re: [PATCH] daemon: --access-hook option
Date: Tue, 21 Aug 2012 12:57:35 +0200 [thread overview]
Message-ID: <5033699F.5030207@redhat.com> (raw)
In-Reply-To: <7vobmc7n80.fsf_-_@alter.siamese.dyndns.org>
Right, this approach of having ACL using the --access-hook option looks
much better. At least you got inspired this could be useful for somebody ;-)
Michal
On 08/15/2012 07:12 AM, Junio C Hamano wrote:
> The --access-hook option to "git daemon" specifies an external
> command to be run every time a client connects, with
>
> - service name (e.g. "upload-pack", etc.),
> - path to the repository,
> - hostname (%H),
> - canonical hostname (%CH),
> - ip address (%IP),
> - tcp port (%P)
>
> as its command line arguments. The external command can decide to
> decline the service by exiting with a non-zero status (or to allow it
> by exiting with a zero status). It can also look at the $REMOTE_ADDR
> and $REMOTE_PORT environment variables to learn about the requestor
> when making this decision.
>
> The external command can optionally write a single line to its
> standard output to be sent to the requestor as an error message when
> it declines the service.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
> * This time, minimally tested, with a documentation update.
>
> Documentation/git-daemon.txt | 16 +++++++++
> daemon.c | 77 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 93 insertions(+)
>
> diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
> index 31b28fc..c3ba4d7 100644
> --- a/Documentation/git-daemon.txt
> +++ b/Documentation/git-daemon.txt
> @@ -16,6 +16,7 @@ SYNOPSIS
> [--reuseaddr] [--detach] [--pid-file=<file>]
> [--enable=<service>] [--disable=<service>]
> [--allow-override=<service>] [--forbid-override=<service>]
> + [--access-hook=<path>]
> [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
> [<directory>...]
>
> @@ -171,6 +172,21 @@ the facility of inet daemon to achieve the same before spawning
> errors are not enabled, all errors report "access denied" to the
> client. The default is --no-informative-errors.
>
> +--access-hook=<path>::
> + Every time a client connects, first run an external command
> + specified by the <path> with service name (e.g. "upload-pack"),
> + path to the repository, hostname (%H), canonical hostname
> + (%CH), ip address (%IP), and tcp port (%P) as its command line
> + arguments. The external command can decide to decline the
> + service by exiting with a non-zero status (or to allow it by
> + exiting with a zero status). It can also look at the $REMOTE_ADDR
> + and $REMOTE_PORT environment variables to learn about the
> + requestor when making this decision.
> ++
> +The external command can optionally write a single line to its
> +standard output to be sent to the requestor as an error message when
> +it declines the service.
> +
> <directory>::
> A directory to add to the whitelist of allowed directories. Unless
> --strict-paths is specified this will also include subdirectories
> diff --git a/daemon.c b/daemon.c
> index ab21e66..4602b46 100644
> --- a/daemon.c
> +++ b/daemon.c
> @@ -30,6 +30,7 @@ static const char daemon_usage[] =
> " [--interpolated-path=<path>]\n"
> " [--reuseaddr] [--pid-file=<file>]\n"
> " [--(enable|disable|allow-override|forbid-override)=<service>]\n"
> +" [--access-hook=<path>]\n"
> " [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
> " [--detach] [--user=<user> [--group=<group>]]\n"
> " [<directory>...]";
> @@ -256,6 +257,71 @@ static int daemon_error(const char *dir, const char *msg)
> return -1;
> }
>
> +static char *access_hook;
> +
> +static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
> +{
> + struct child_process child;
> + struct strbuf buf = STRBUF_INIT;
> + const char *argv[8];
> + const char **arg = argv;
> + char *eol;
> + int seen_errors = 0;
> +
> +#define STRARG(x) ((x) ? (x) : "")
> + *arg++ = access_hook;
> + *arg++ = service->name;
> + *arg++ = path;
> + *arg++ = STRARG(hostname);
> + *arg++ = STRARG(canon_hostname);
> + *arg++ = STRARG(ip_address);
> + *arg++ = STRARG(tcp_port);
> + *arg = NULL;
> +#undef STRARG
> +
> + memset(&child, 0, sizeof(child));
> + child.use_shell = 1;
> + child.argv = argv;
> + child.no_stdin = 1;
> + child.no_stderr = 1;
> + child.out = -1;
> + if (start_command(&child)) {
> + logerror("daemon access hook '%s' failed to start",
> + access_hook);
> + goto error_return;
> + }
> + if (strbuf_read(&buf, child.out, 0) < 0) {
> + logerror("failed to read from pipe to daemon access hook '%s'",
> + access_hook);
> + strbuf_reset(&buf);
> + seen_errors = 1;
> + }
> + if (close(child.out) < 0) {
> + logerror("failed to close pipe to daemon access hook '%s'",
> + access_hook);
> + seen_errors = 1;
> + }
> + if (finish_command(&child))
> + seen_errors = 1;
> +
> + if (!seen_errors) {
> + strbuf_release(&buf);
> + return 0;
> + }
> +
> +error_return:
> + strbuf_ltrim(&buf);
> + if (!buf.len)
> + strbuf_addstr(&buf, "service rejected");
> + eol = strchr(buf.buf, '\n');
> + if (eol)
> + *eol = '\0';
> + errno = EACCES;
> + daemon_error(dir, buf.buf);
> + strbuf_release(&buf);
> + return -1;
> +}
> +
> static int run_service(char *dir, struct daemon_service *service)
> {
> const char *path;
> @@ -304,6 +370,13 @@ static int run_service(char *dir, struct daemon_service *service)
> }
>
> /*
> + * Optionally, a hook can choose to deny access to the
> + * repository depending on the phase of the moon.
> + */
> + if (access_hook && run_access_hook(service, dir, path))
> + return -1;
> +
> + /*
> * We'll ignore SIGTERM from now on, we have a
> * good client.
> */
> @@ -1142,6 +1215,10 @@ int main(int argc, char **argv)
> export_all_trees = 1;
> continue;
> }
> + if (!prefixcmp(arg, "--access-hook=")) {
> + access_hook = arg + 14;
> + continue;
> + }
> if (!prefixcmp(arg, "--timeout=")) {
> timeout = atoi(arg+10);
> continue;
--
Michal Novotny <minovotn@redhat.com>, RHCE, Red Hat
Virtualization | libvirt-php bindings | php-virt-control.org
prev parent reply other threads:[~2012-08-21 10:57 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-14 9:59 [PATCH] Implement ACL module architecture and sample MySQL ACL module Michal Novotny
2012-08-14 16:12 ` Junio C Hamano
2012-08-14 16:27 ` Shawn Pearce
2012-08-14 17:06 ` Junio C Hamano
2012-08-14 17:26 ` Shawn Pearce
2012-08-14 18:37 ` Junio C Hamano
2012-08-15 5:12 ` [PATCH] daemon: --access-hook option Junio C Hamano
2012-08-15 14:08 ` Shawn Pearce
2012-08-21 10:57 ` Michal Novotny [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5033699F.5030207@redhat.com \
--to=minovotn@redhat.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.