Skip to contentSkip to conversation

full featured formating function of the --{base,user}_path arguments,

PATCH In review Pierre Habouzit 2 participants 3 messages Jun 15, 2016 Documentation

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 full featured formating function of the --{base,user}_path arguments,

---
 Documentation/git-daemon.txt |   54 +++++++++++
 daemon.c                     |  207 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 240 insertions(+), 21 deletions(-)
Documentation/git-daemon.txt +53 -1
index 0f7d274..796ae7e 100644
@@ -11,6 +11,8 @@ SYNOPSIS
 'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
              [--timeout=n] [--init-timeout=n] [--strict-paths]
              [--base-path=path] [--user-path | --user-path=path]
+             [--base-path-fmt=pathfmt] [--user-path-fmt=pathfmt]
+             [--default-hostname=hostname]
 	     [--reuseaddr] [--detach] [--pid-file=file] [directory...]
 
 DESCRIPTION
@@ -45,6 +47,10 @@ OPTIONS
 	'git://example.com/hello.git', `git-daemon` will interpret the path
 	as '/srv/git/hello.git'.
 
+--base-path-fmt=pathfmt::
+	Works like --base-path, but uses a format instead. See Path
+	Formats section below.
+
 --export-all::
 	Allow pulling from all directories that look like GIT repositories
 	(have the 'objects' and 'refs' subdirectories), even if they
@@ -79,9 +85,20 @@ OPTIONS
 	taken as a request to access `path/foo` repository in
 	the home directory of user `alice`.
 
+--user-path-fmt=pathfmt::
+	Allow ~user notation to be used in requests. The path used to look
+	for the git repository is a format string, see Path Formats
+	section below.
+
 --verbose::
 	Log details about the incoming connections and requested files.
 
+--default-hostname=hostname::
+	Backward compatibility switch: argument is used as a fallback
+	hostname to use with virtual hosting (to fill the `%h` format in
+	path formats) when the client is too old to provide the information
+	in the query (older than 1.4.0 series).
+
 --reuseaddr::
 	Use SO_REUSEADDR when binding the listening socket.
 	This allows the server to restart without waiting for
@@ -98,10 +115,45 @@ OPTIONS
 	--strict-paths is specified this will also include subdirectories
 	of each named directory.
 
+Path Formats
+------------
+
+%h::
+	requested hostname. That won't work with clients older than 1.4.0
+	that do not pass the hostname in their query, and in that case, the
+	value of --default-hostname (if any) is used.
+
+%p::
+	requested path.
+
+%P::
+	requested path without the first slash when exists (`/`).
+
+%u::
+	requested username (only allowed for --user-path-fmt).
+
+%%::
+	plain `%`.
+
+Examples
+~~~~~~~~
+
+* `--base-path-fmt=/srv/git/%P` emulates `--base-path=/srv/git`
+
+* `--base-path-fmt=/srv/git/%h%p` will look into
+  `/srv/git/git.example.com/foo` if the request goes to
+  git://git.example.com/foo
+
+* `--user-path-fmt=/home/%u/public_git/%P` works mostly like
+  `--user-path=public_git` (the difference is that it assumes that home
+  directories live in `/home/username` instead of using the real `username`
+  home).
+
 Author
 ------
 Written by Linus Torvalds <[email protected]>, YOSHIFUJI Hideaki
-<[email protected]> and the git-list <[email protected]>
+<[email protected]>, Pierre Habouzit <[email protected]>,
+and the git-list <[email protected]>
 
 Documentation
 --------------
daemon.c +187 -20

307 lines not on this page · raw message

Signature · 1 line
1.4.1.1
#1 lore raw
Quoted 4 lines · Pierre Habouzit
daemon.c +4 -0
+static struct {
+	const char *path;
+	int use_as_fmt;
+} base_path;

daemon.c static int strict_paths; · line 46

Quoted 10 lines
daemon.c +4 -1
 
 /* If defined, ~user notation is allowed and the string is inserted
  * after ~user/.  E.g. a request to git://host/~alice/frotz would
  * go to /home/alice/pub_git/frotz with --user-path=pub_git.
  */
-static const char *user_path;
+static struct {
+	const char *path;
+	int use_as_fmt;
+} user_path;

Maybe it does not matter much, but I wonder if we want to keep two structs the same type, like:

        static struct {
                const char *path;
                int use_as_fmt;
        } base_path, user_path;

I also wondered if we can just extend the semantics of base_path and user_path to autodetect the fmt-ness of them, but that means we would break existing setups that uses per-cent in the pathname. Arguably that would not be so common and we may not need to worry about such an installation, though. What do you think?

Quoted 4 lines
daemon.c +0 -0
@@ -174,24 +285,45 @@ static char *path_ok(char *dir)
 				slash = dir + restlen;
 			namlen = slash - dir;
 			restlen -= namlen;

daemon.c static char *path_ok(char *dir) · line 297

Quoted 10 lines
daemon.c +10 -0
+
+			if (user_path.use_as_fmt) {
+				loginfo("host <%s>, "
+					"userpathfmt <%s>, request <%s>, "
+					"namlen %d, restlen %d, slash <%s>",
+					vhost,
+					user_path.path, dir,
+					namlen, restlen, slash);
+				dir = git_path_fmt(rpath, user_path.path, vhost,
+						   slash, dir + 1, namlen - 1);

When vhost is NULL you would feed it to "%s", which I think glibc works around with (null) fine but other C libraries would not like it. git_path_fmt()'s logging does not have this problem, though.

daemon.c static char *path_ok(char *dir) · line 319

Quoted 11 lines
daemon.c +6 -0
+	else if (base_path.path) {
 		if (*dir != '/') {
 			/* Allow only absolute */
 			logerror("'%s': Non-absolute path denied (base-path active)", dir);
 			return NULL;
 		}
+
+		if (base_path.use_as_fmt) {
+			dir = git_base_path_fmt(rpath, base_path.path, vhost, dir);
+		} else {
+			snprintf(rpath, PATH_MAX, "%s%s", base_path.path, dir);

The level of logging in this branch and in user_path.use_as_fmt branch are inconsistent. Maybe the more detailed one above I commented about vhost==NULL case was primarily meant for debugging and you forgot to remove it?

Quoted 14 lines
daemon.c +7 -0
@@ -274,6 +406,7 @@ static int execute(struct sockaddr *addr
@@ -303,15 +436,30 @@ #endif
 	alarm(0);
 
 	len = strlen(line);
+
+	if (pktlen != len) {
+		int arg_pos = len + 1;
+
 		loginfo("Extended attributes (%d bytes) exist <%.*s>",
 			(int) pktlen - len,
+			(int) pktlen - len, line + arg_pos);
+
+		while (arg_pos < pktlen) {

daemon.c #endif · line 457

Quoted 10 lines
daemon.c +10 -0
+			int arg_len = strlen(line + arg_pos);
+
+			if (!strncmp("host=", line + arg_pos, 5)) {
+				vhost = line + arg_pos + 5;
+			}
+
+			arg_pos += arg_len + 1;
+		}
+	}
+

I think it is easier to do:

	if (!vhost)
        	vhost = default_host;

and have git_base_path_fmt() barf if the format calls for %h and vhost passed to it is NULL. Lack of "host=" in the request is logged here already.

#2 lore raw
Quoted 24 lines · Junio C Hamano
Quoted 9 lines · Pierre Habouzit
daemon.c +4 -0
+static struct {
+	const char *path;
+	int use_as_fmt;
+} base_path;
 
 /* If defined, ~user notation is allowed and the string is

inserted * after ~user/. E.g. a request to git://host/~alice/frotz
would * go to /home/alice/pub_git/frotz with --user-path=pub_git. */

daemon.c static int strict_paths; · line 46

Quoted 5 lines
daemon.c +4 -1
-static const char *user_path;
+static struct {
+	const char *path;
+	int use_as_fmt;
+} user_path;

Maybe it does not matter much, but I wonder if we want to keep two structs the same type, like:

        static struct {
                const char *path;
                int use_as_fmt;
        } base_path, user_path;
Quoted 6 lines

I also wondered if we can just extend the semantics of base_path and user_path to autodetect the fmt-ness of them, but that means we would break existing setups that uses per-cent in the pathname. Arguably that would not be so common and we may not need to worry about such an installation, though. What do you think?

I think that merging the structs is indeed good, but that I do not like to break (even non common) setups when avoidable. but well, I've no *very* strong opinion on this, and if the consensus is that extending the argument with a format is good enough, I'll go for it, it would simplify the code a bit, and remove two arguments, both are good.

Quoted 12 lines
Quoted 12 lines
daemon.c +7 -0
@@ -174,24 +285,45 @@ static char *path_ok(char *dir)
 				slash = dir + restlen;
 			namlen = slash - dir;
 			restlen -= namlen;
+
+			if (user_path.use_as_fmt) {
+				loginfo("host <%s>, "
+					"userpathfmt <%s>, request <%s>, "
+					"namlen %d, restlen %d, slash <%s>",
+					vhost,
+					user_path.path, dir,
Quoted 8 lines

daemon.c static char *path_ok(char *dir) · line 297

Quoted 3 lines
daemon.c +3 -0
+					namlen, restlen, slash);
+				dir = git_path_fmt(rpath, user_path.path, vhost,
+						   slash, dir + 1, namlen - 1);

When vhost is NULL you would feed it to "%s", which I think glibc works around with (null) fine but other C libraries would not like it. git_path_fmt()'s logging does not have this problem, though.

uuhhh, I've always thought that passing NULL to a %s format was allowed by the C standard ... I've no copy here but one at work, I will verify it (for my peace of mind) but I agree it's not pretty.

Quoted 8 lines
Quoted 8 lines
daemon.c +3 -0
+	else if (base_path.path) {
 		if (*dir != '/') {
 			/* Allow only absolute */
 			logerror("'%s': Non-absolute path denied (base-path active)",
 dir); return NULL;
 		}
+
+		if (base_path.use_as_fmt) {
Quoted 8 lines

daemon.c static char *path_ok(char *dir) · line 319

Quoted 3 lines
daemon.c +3 -0
+			dir = git_base_path_fmt(rpath, base_path.path, vhost, dir);
+		} else {
+			snprintf(rpath, PATH_MAX, "%s%s", base_path.path, dir);

The level of logging in this branch and in user_path.use_as_fmt branch are inconsistent. Maybe the more detailed one above I commented about vhost==NULL case was primarily meant for debugging and you forgot to remove it?

well, it was here before, so I left it, but I do not liked it much either, so if it's ok to remove it, I'd be glad to.

Quoted 27 lines
Quoted 14 lines
daemon.c +7 -0
@@ -274,6 +406,7 @@ static int execute(struct sockaddr *addr
@@ -303,15 +436,30 @@ #endif
 	alarm(0);
 
 	len = strlen(line);
+
+	if (pktlen != len) {
+		int arg_pos = len + 1;
+
 		loginfo("Extended attributes (%d bytes) exist <%.*s>",
 			(int) pktlen - len,
+			(int) pktlen - len, line + arg_pos);
+
+		while (arg_pos < pktlen) {

daemon.c #endif · line 457

Quoted 10 lines
daemon.c +10 -0
+			int arg_len = strlen(line + arg_pos);
+
+			if (!strncmp("host=", line + arg_pos, 5)) {
+				vhost = line + arg_pos + 5;
+			}
+
+			arg_pos += arg_len + 1;
+		}
+	}
+

I think it is easier to do:

Quoted 6 lines
	if (!vhost)
        	vhost = default_host;

and have git_base_path_fmt() barf if the format calls for %h and vhost passed to it is NULL. Lack of "host=" in the request is logged here already.

hmmm, lack of host= is only logged in the git_path_fmt function atm. Its presence is logged though. But I could obviously log that it's missing while parsing the extending attributes, and then only need to barf when the %h is actually needed in the format string. That seems indeed easier. Will do.

Signature · 3 lines
·O·  Pierre Habouzit
··O                                                [email protected]
OOO                                                http://www.madism.org