{"thread":{"id":"2191","subject":"Server side programs","startedAt":"2005-10-22T22:22:17Z","lastAt":"2005-10-27T08:34:12Z","messageCount":30,"participants":["Andreas Ericsson","Junio C Hamano","Linus Torvalds","Petr Baudis","H. Peter Anvin","Daniel Barkalow","Matthias Urlichs"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"10469","messageId":"435ABB99.5020908@op5.se","threadId":"2191","inReplyTo":null,"subject":"Server side programs","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-22T22:22:17Z","receivedAt":"2005-10-22T22:22:17Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Are git-receive-pack and git-upload-pack the only two binaries that get \ncalled directly over a SSH-tunnel?\n\nThe git tutorial explicitly mentions this for git-receive-pack. Several \nof the other docs (git-fetch-pack, git-peek-remote and git-clone-pack) \nmentions git-upload-pack. No other program from the git suite is \nmentioned as an immediate target for ssh connections.\n\nThe reason I'm asking is that I'm adding support for userrelative paths \n(git pull ssh://host:~user/somedir) and removing the possibilities to \nuse a compromised but limited account for finding out what other \nuseraccounts are available.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"10471","messageId":"7vll0l6pn7.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"435ABB99.5020908@op5.se","subject":"Re: Server side programs","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T00:30:36Z","receivedAt":"2005-10-23T00:30:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> Are git-receive-pack and git-upload-pack the only two binaries that get \n> called directly over a SSH-tunnel?\n\nThere are git-ssh-fetch and git-ssh-upload which call each other\n(and the older name pairs git-ssh-push and git-sh-pull do so as\nwell).  However, you do not have to use these commit walkers\nover ssh; fetch-pack/upload-pack pair work quite well.\n\nI think your question is \"what is the absolute minimum set of\nbinaries you need to allow\", so I think the two listed are\nenough.  If you want to let your users coming over SSH *create*\na new repository on your machine, you would need a bit more,\nthough (namely, shell access to run mkdir and git-init-db).\n\n> The reason I'm asking is that I'm adding support for userrelative paths \n> (git pull ssh://host:~user/somedir) and removing the possibilities to \n> use a compromised but limited account for finding out what other \n> useraccounts are available.\n\nSorry, it is not clear to me what you are adding.  I do this\nregularly:\n\n\t$ git push kernel.org:git/\n\t$ git fetch kernel.org:git/\n\nto push into and fetch from $HOME/git/ repository on the other\nend.\n\nAlso I can do this already (assuming the other end hangs all\nusers under the same directory, presumably /home/$user):\n\n\t$ git fetch kernel.org:../torvalds/git/\n\nAre you in addition trying to let me do this:\n\n\t$ git fetch kernel.org:~torvalds/git/\n\nwhich would work even when ~torvalds == /home/torvalds and\n~junio == /home2/junio, without having to tell people where\nthe user home directories are?\n\nAt one point, Linus posted an outline of \"restricted login shell\nfor use with git over ssh\".  I think you could start from there,\nperhaps extend it so that it checks the binaries *and* pathnames\nthe user can specify (e.g. only under your own $HOME is allowed,\nand no /../ in them, or something silly like that).\n"},{"id":"10472","messageId":"Pine.LNX.4.64.0510221737300.10477@g5.osdl.org","threadId":"2191","inReplyTo":"435ABB99.5020908@op5.se","subject":"Re: Server side programs","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-23T00:42:10Z","receivedAt":"2005-10-23T00:42:10Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 23 Oct 2005, Andreas Ericsson wrote:\n>\n> Are git-receive-pack and git-upload-pack the only two binaries that get called\n> directly over a SSH-tunnel?\n\nWith the normal pack thing, yes.\n\nThey will exec other programs (mainly git-rev-list and \ngit-[un]pack-objects), and a client can ask for other programs \n(git-send-pack takes an \"--exec=\" argument, for example), but those two \nshould be sufficient if you have a server-side special \"restricted shell\" \nthat you want to run instead of a real one.\n\nOne more issue: you can't create a new archive or delete an old one (or do \nadministration like repacking, fsck etc) with those interfaces, so if you \nwant these limited users to be able to do that, then you'd need to add a \nfew administration commands too.\n\n\t\tLinus\n"},{"id":"10481","messageId":"435B5AE0.1060400@op5.se","threadId":"2191","inReplyTo":"7vll0l6pn7.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths (was: Server side programs)","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-23T09:41:52Z","receivedAt":"2005-10-23T09:41:52Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Andreas Ericsson <ae@op5.se> writes:\n> \n> \n>>Are git-receive-pack and git-upload-pack the only two binaries that get \n>>called directly over a SSH-tunnel?\n> \n> \n> There are git-ssh-fetch and git-ssh-upload which call each other\n> (and the older name pairs git-ssh-push and git-sh-pull do so as\n> well).  However, you do not have to use these commit walkers\n> over ssh; fetch-pack/upload-pack pair work quite well.\n> \n> I think your question is \"what is the absolute minimum set of\n> binaries you need to allow\", so I think the two listed are\n> enough.  If you want to let your users coming over SSH *create*\n> a new repository on your machine, you would need a bit more,\n> though (namely, shell access to run mkdir and git-init-db).\n> \n\nThat's good to know.\n\n> \n>>The reason I'm asking is that I'm adding support for userrelative paths \n>>(git pull ssh://host:~user/somedir) and removing the possibilities to \n>>use a compromised but limited account for finding out what other \n>>useraccounts are available.\n> \n> \n> Sorry, it is not clear to me what you are adding.  I do this\n> regularly:\n> \n> \t$ git push kernel.org:git/\n> \t$ git fetch kernel.org:git/\n> \n> to push into and fetch from $HOME/git/ repository on the other\n> end.\n> \n\nLooking at the old code I see that that should work. I'll re-work the \npatch to take this into account. The help-text was a bit fuzzy however, \nand if you tried\n\n\t$ git fetch ssh://kernel.org:git\n\nit wouldn't work. Here's how I decided it was somehow broken, or at \nleast non-intuitive:\n\n\t$ git clone ssh://git.op5.se:git foo\n\tdefaulting to local storage area\n\tssh: ssh: Name or service not known\n\tfatal: unexpected EOF\n\n\n> Also I can do this already (assuming the other end hangs all\n> users under the same directory, presumably /home/$user):\n> \n> \t$ git fetch kernel.org:../torvalds/git/\n> \n> Are you in addition trying to let me do this:\n> \n> \t$ git fetch kernel.org:~torvalds/git/\n> \n> which would work even when ~torvalds == /home/torvalds and\n> ~junio == /home2/junio, without having to tell people where\n> the user home directories are?\n> \n\nYes. Our servers' home-directories have varying paths and it'd be nice \nto be able to pull other team-members code without having to remember \nhow that particular server is configured.\n\n> At one point, Linus posted an outline of \"restricted login shell\n> for use with git over ssh\".  I think you could start from there,\n> perhaps extend it so that it checks the binaries *and* pathnames\n> the user can specify (e.g. only under your own $HOME is allowed,\n> and no /../ in them, or something silly like that).\n> \n\nI found this in the archives:\nhttp://article.gmane.org/gmane.comp.version-control.git/5784/match=restricted+login\n\nIs that what you're referring to?\n\nThere's no reason why git-upload-pack and git-receive-pack couldn't be \nused safely with a perfectly ordinary shell provided we're careful about \ngiving the same error message for when a directory is missing and when \nit isn't a git archive.\n\nAnyways, the attached patch does this. I've tested all the various \nsyntaxes and they work as expected. rsync, http and local files take the \nsame syntax as before. I haven't added support for user-relative paths \nto the git-daemon (can't see the point, really) although that can be \ndone easily enough.\n\nThis patch works without conflicts alongside Johannes Schindelin's \nrecent contribution.\n\nLet me know if you want things done differently.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\n\ndiff --git a/Makefile b/Makefile\nindex 903c57c..87188ea 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -115,15 +115,18 @@ PROGRAMS = \\\n \tgit-local-fetch$X git-ls-files$X git-ls-tree$X git-merge-base$X \\\n \tgit-merge-index$X git-mktag$X git-pack-objects$X git-patch-id$X \\\n \tgit-peek-remote$X git-prune-packed$X git-read-tree$X \\\n-\tgit-receive-pack$X git-rev-list$X git-rev-parse$X \\\n+\tgit-rev-list$X git-rev-parse$X \\\n \tgit-send-pack$X git-show-branch$X \\\n \tgit-show-index$X git-ssh-fetch$X \\\n \tgit-ssh-upload$X git-tar-tree$X git-unpack-file$X \\\n \tgit-unpack-objects$X git-update-index$X git-update-server-info$X \\\n-\tgit-upload-pack$X git-verify-pack$X git-write-tree$X \\\n+\tgit-verify-pack$X git-write-tree$X \\\n \tgit-update-ref$X git-symbolic-ref$X git-check-ref-format$X \\\n \t$(SIMPLE_PROGRAMS)\n \n+# server side programs called (possibly) over an ssh-tunnel\n+SERVERSIDE_PROGRAMS = git-receive-pack$X git-upload-pack$X\n+\n # Backward compatibility -- to be removed after 1.0\n PROGRAMS += git-ssh-pull$X git-ssh-push$X\n \n@@ -315,7 +318,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)\n export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir\n ### Build rules\n \n-all: $(PROGRAMS) $(SCRIPTS)\n+all: $(PROGRAMS) $(SCRIPTS) $(SERVERSIDE_PROGRAMS)\n \n all:\n \t$(MAKE) -C templates\n@@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n %.o: %.S\n \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n \n+$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n+\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n+\n git-%$X: %.o $(LIB_FILE)\n \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n \n@@ -383,6 +389,7 @@ init-db.o: init-db.c\n \n $(LIB_OBJS): $(LIB_H)\n $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H)\n+$(patsubst git-%$X,%.o,$(SERVERSIDE_PROGRAMS)): $(LIB_H) srvside-ssh.o\n $(DIFF_OBJS): diffcore.h\n \n $(LIB_FILE): $(LIB_OBJS)\n@@ -410,9 +417,10 @@ check:\n \n ### Installation rules\n \n-install: $(PROGRAMS) $(SCRIPTS)\n+install: $(PROGRAMS) $(SCRIPTS) $(SERVERSIDE_PROGRAMS)\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))\n-\t$(INSTALL) $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) $(PROGRAMS) $(SERVERSIDE_PROGRAMS) $(SCRIPTS) \\\n+\t\t$(call shellquote,$(DESTDIR)$(bindir))\n \tsh ./cmd-rename.sh $(call shellquote,$(DESTDIR)$(bindir))\n \t$(MAKE) -C templates install\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\ndiff --git a/connect.c b/connect.c\nindex b171c5d..0d78b3e 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -436,33 +436,44 @@ static int git_tcp_connect(int fd[2], co\n int git_connect(int fd[2], char *url, const char *prog)\n {\n \tchar command[1024];\n-\tchar *host, *path;\n-\tchar *colon;\n+\tchar *host, *path, *ptr = NULL;\n \tint pipefd[2][2];\n \tpid_t pid;\n \tenum protocol protocol;\n \n+\tprotocol = PROTO_LOCAL;\n \thost = NULL;\n \tpath = url;\n-\tcolon = strchr(url, ':');\n-\tprotocol = PROTO_LOCAL;\n-\tif (colon) {\n-\t\t*colon = 0;\n-\t\thost = url;\n-\t\tpath = colon+1;\n-\t\tprotocol = PROTO_SSH;\n-\t\tif (!memcmp(path, \"//\", 2)) {\n-\t\t\tchar *slash = strchr(path + 2, '/');\n-\t\t\tif (slash) {\n-\t\t\t\tint nr = slash - path - 2;\n-\t\t\t\tmemmove(path, path+2, nr);\n-\t\t\t\tpath[nr] = 0;\n-\t\t\t\tprotocol = get_protocol(url);\n-\t\t\t\thost = path;\n-\t\t\t\tpath = slash;\n-\t\t\t}\n+\thost = strstr(url, \"://\");\n+\tif (host) {\n+\t\t*host = '\\0';\n+\t\thost += 3;\n+\t\tprotocol = get_protocol(url);\n+\t}\n+\telse host = url;\n+\n+\tptr = strchr(host, ':');\n+\tpath = strchr(host, '/');\n+\n+\t/* leading colon marks relative path for ssh.\n+\t * Check for host == url and default to PROTO_SSH to allow\n+\t *   $ git fetch kernel.org:git\n+\t */\n+\tif(ptr && (!path || ptr < path)) {\n+\t\tif(host == url)\n+\t\t\tprotocol = PROTO_SSH;\n+\n+\t\tif(protocol == PROTO_SSH) {\n+\t\t\t*ptr = '\\0';\n+\t\t\tpath = ptr + 1;\n \t\t}\n \t}\n+\telse if(path != url) {\n+\t\t/* null-terminate host and copy path if it isn't relative */\n+\t\tptr = strdup(path);\n+\t\t*path = '\\0';\n+\t\tpath = ptr;\n+\t}\n \n \tif (protocol == PROTO_GIT)\n \t\treturn git_tcp_connect(fd, prog, host, path);\ndiff --git a/receive-pack.c b/receive-pack.c\nindex 8f157bc..9a040ff 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -8,6 +8,8 @@ static const char receive_pack_usage[] =\n \n static const char unpacker[] = \"git-unpack-objects\";\n \n+extern void srvside_chdir(const char *path, int strict);\n+\n static int show_ref(const char *path, const unsigned char *sha1)\n {\n \tpacket_write(1, \"%s %s\\n\", sha1_to_hex(sha1), path);\n@@ -265,18 +267,9 @@ int main(int argc, char **argv)\n \tif (!dir)\n \t\tusage(receive_pack_usage);\n \n-\t/* chdir to the directory. If that fails, try appending \".git\" */\n-\tif (chdir(dir) < 0) {\n-\t\tif (chdir(mkpath(\"%s.git\", dir)) < 0)\n-\t\t\tdie(\"unable to cd to %s\", dir);\n-\t}\n-\n-\t/* If we have a \".git\" directory, chdir to it */\n-\tchdir(\".git\");\n-\tputenv(\"GIT_DIR=.\");\n+\t/* Find the right directory */\n+\tsrvside_chdir(dir, 0);\n \n-\tif (access(\"objects\", X_OK) < 0 || access(\"refs/heads\", X_OK) < 0)\n-\t\tdie(\"%s doesn't appear to be a git directory\", dir);\n \twrite_head_info();\n \n \t/* EOF */\ndiff --git a/srvside-ssh.c b/srvside-ssh.c\nnew file mode 100644\nindex 0000000..0ed5d30\n--- /dev/null\n+++ b/srvside-ssh.c\n@@ -0,0 +1,63 @@\n+#include \"cache.h\"\n+#include <unistd.h>\n+#include <pwd.h>\n+\n+extern const char *__progname;\n+\n+\n+/*\n+ * Provide support for user-relative paths, but carefully.\n+ *\n+ * If someone has compromised an account with access limited to a few\n+ * commands (git-receive-pack, git-upload-pack) we don't want to let\n+ * them find out about other users through git.  We prevent that by the\n+ * simple expedient of maintaining the 'path' variable as is and always\n+ * supplying the same (not entirely) helpful error message.\n+ */\n+#define DIR_OOPS \\\n+\tdie(\"%s: '%s': unable to chdir or not a git-archive\", __progname, path)\n+void srvside_chdir(char *path, int strict)\n+{\n+\tchar *dir = path;\n+\tstruct passwd *pw;\n+\n+\tif(chdir(path) < 0 && *path == '~') {\n+\t\tchar *slash;\n+\t\tchar *user = (char *)path + 1;\n+\n+\t\tif((slash = strchr(dir, '/')))\n+\t\t\t*slash = '\\0';\n+\n+\t\tif(!(pw = getpwnam(user))) {\n+\t\t\tif(slash)\n+\t\t\t\t*slash = '/';\n+\t\t\tDIR_OOPS;\n+\t\t}\n+\t\tif(chdir(pw->pw_dir) < 0) {\n+\t\t\tDIR_OOPS;\n+\t\t}\n+\n+\t\t/* We're in someones homedir so re-insert the slash (for the\n+\t\t * error message) and set dir just beyond it. If there was no\n+\t\t * spoon we supply the local one */\n+\t\tif(slash) {\n+\t\t\t*slash = '/';\n+\t\t\tdir = slash + 1;\n+\t\t}\n+\t\telse\n+\t\t\tdir = \"./\";\n+\t}\n+\n+\t/* chdir to the directory. If that fails, try appending \".git\" */\n+\tif (chdir(dir) < 0) {\n+\t\tif (strict || chdir(mkpath(\"%s.git\", dir)) < 0)\n+\t\t\tDIR_OOPS;\n+\t}\n+\tif (!strict)\n+\t\tchdir(\".git\");\n+\n+\tif (access(\"objects\", X_OK) || access(\"refs\", X_OK))\n+\t\tDIR_OOPS;\n+\n+\tputenv(\"GIT_DIR=.\");\n+}\ndiff --git a/upload-pack.c b/upload-pack.c\nindex accdba6..356c9b1 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -5,6 +5,7 @@\n #include \"object.h\"\n \n static const char upload_pack_usage[] = \"git-upload-pack [--strict] [--timeout=nn] <dir>\";\n+extern void srvside_chdir(const char *path, int strict);\n \n #define MAX_HAS 256\n #define MAX_NEEDS 256\n@@ -202,7 +203,6 @@ static int upload_pack(void)\n \n int main(int argc, char **argv)\n {\n-\tconst char *dir;\n \tint i;\n \tint strict = 0;\n \n@@ -227,20 +227,10 @@ int main(int argc, char **argv)\n \t\n \tif (i != argc-1)\n \t\tusage(upload_pack_usage);\n-\tdir = argv[i];\n \n-\t/* chdir to the directory. If that fails, try appending \".git\" */\n-\tif (chdir(dir) < 0) {\n-\t\tif (strict || chdir(mkpath(\"%s.git\", dir)) < 0)\n-\t\t\tdie(\"git-upload-pack unable to chdir to %s\", dir);\n-\t}\n-\tif (!strict)\n-\t\tchdir(\".git\");\n-\n-\tif (access(\"objects\", X_OK) || access(\"refs\", X_OK))\n-\t\tdie(\"git-upload-pack: %s doesn't seem to be a git archive\", dir);\n+\t/* Find the right directory */\n+\tsrvside_chdir(argv[i], strict);\n \n-\tputenv(\"GIT_DIR=.\");\n \tupload_pack();\n \treturn 0;\n }\n"},{"id":"10488","messageId":"20051023183757.GS30889@pasky.or.cz","threadId":"2191","inReplyTo":"435B5AE0.1060400@op5.se","subject":"Re: User-relative paths (was: Server side programs)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-10-23T18:37:57Z","receivedAt":"2005-10-23T18:37:57Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Sun, Oct 23, 2005 at 11:41:52AM CEST, I got a letter\nwhere Andreas Ericsson <ae@op5.se> told me that...\n> Anyways, the attached patch does this. I've tested all the various \n> syntaxes and they work as expected. rsync, http and local files take the \n> same syntax as before. I haven't added support for user-relative paths \n> to the git-daemon (can't see the point, really) although that can be \n> done easily enough.\n\nIt would be useful to add a [PATCH] tag to subject when you submit a\npatch, so that we notice it better. ;-)\n\nYou don't update the documentation even though there seem to be some\nsyntactic changes. You should at least update\n\n\tDocumentation/pull-fetch-param.txt\n\nAlso before Junio asks you, in the followup patches, you might want to\nsign off the patch if you want it integrated.\n\n> diff --git a/Makefile b/Makefile\n> index 903c57c..87188ea 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n>  %.o: %.S\n>  \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n>  \n> +$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n> +\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n> +\n>  git-%$X: %.o $(LIB_FILE)\n>  \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n>  \n\nWhy are you adding own compilation command, and why is it inconsistent\nwith the git-%$X's one?\n\n> diff --git a/connect.c b/connect.c\n> index b171c5d..0d78b3e 100644\n> --- a/connect.c\n> +++ b/connect.c\n> @@ -436,33 +436,44 @@ static int git_tcp_connect(int fd[2], co\n> +\t/* leading colon marks relative path for ssh.\n> +\t * Check for host == url and default to PROTO_SSH to allow\n> +\t *   $ git fetch kernel.org:git\n> +\t */\n> +\tif(ptr && (!path || ptr < path)) {\n> +\t\tif(host == url)\n> +\t\t\tprotocol = PROTO_SSH;\n> +\n> +\t\tif(protocol == PROTO_SSH) {\n> +\t\t\t*ptr = '\\0';\n> +\t\t\tpath = ptr + 1;\n>  \t\t}\n>  \t}\n\nIf I understand this right,\n\n\tssh://foo.bar:baz/quux\n\nwill make foo.bar the host and baz/quux the path. Please, do NOT do\nthis! It is supposed to be a URL, dammit! And you know, URLs have\ndefined _syntax_, and that's important at least every time the URL gets\nout of GIT's context. Or stop it calling URL altogether, to prevent any\nconfusion. But in URLs, the space between : and / is a port definition.\nSee also RFC3986 (aka STD066) and RFC2718.\n\nThanks.\n\n> diff --git a/receive-pack.c b/receive-pack.c\n> index 8f157bc..9a040ff 100644\n> --- a/receive-pack.c\n> +++ b/receive-pack.c\n> @@ -265,18 +267,9 @@ int main(int argc, char **argv)\n>  \tif (!dir)\n>  \t\tusage(receive_pack_usage);\n>  \n> -\t/* chdir to the directory. If that fails, try appending \".git\" */\n> -\tif (chdir(dir) < 0) {\n> -\t\tif (chdir(mkpath(\"%s.git\", dir)) < 0)\n> -\t\t\tdie(\"unable to cd to %s\", dir);\n> -\t}\n> -\n> -\t/* If we have a \".git\" directory, chdir to it */\n> -\tchdir(\".git\");\n> -\tputenv(\"GIT_DIR=.\");\n> +\t/* Find the right directory */\n> +\tsrvside_chdir(dir, 0);\n>  \n> -\tif (access(\"objects\", X_OK) < 0 || access(\"refs/heads\", X_OK) < 0)\n> -\t\tdie(\"%s doesn't appear to be a git directory\", dir);\n>  \twrite_head_info();\n>  \n>  \t/* EOF */\n\nNo srvside_chdir() declaration?\n\n> diff --git a/srvside-ssh.c b/srvside-ssh.c\n> new file mode 100644\n> index 0000000..0ed5d30\n> --- /dev/null\n> +++ b/srvside-ssh.c\n> @@ -0,0 +1,63 @@\n> +#include \"cache.h\"\n> +#include <unistd.h>\n> +#include <pwd.h>\n> +\n> +extern const char *__progname;\n\nHow portable is this? It appears that no standard really defines this,\nand Google faintly hints at least some Cygwin-related problems...\n\n> diff --git a/upload-pack.c b/upload-pack.c\n> index accdba6..356c9b1 100644\n> --- a/upload-pack.c\n> +++ b/upload-pack.c\n> @@ -5,6 +5,7 @@\n>  #include \"object.h\"\n>  \n>  static const char upload_pack_usage[] = \"git-upload-pack [--strict] [--timeout=nn] <dir>\";\n> +extern void srvside_chdir(const char *path, int strict);\n>  \n>  #define MAX_HAS 256\n>  #define MAX_NEEDS 256\n\nWhat about a .h file?\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"10495","messageId":"7voe5gypvi.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"20051023183757.GS30889@pasky.or.cz","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T19:50:25Z","receivedAt":"2005-10-23T19:50:25Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>> diff --git a/Makefile b/Makefile\n>> index 903c57c..87188ea 100644\n>> --- a/Makefile\n>> +++ b/Makefile\n>> @@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n>>  %.o: %.S\n>>  \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n>>  \n>> +$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n>> +\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n>> +\n>>  git-%$X: %.o $(LIB_FILE)\n>>  \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n>>  \n>\n> Why are you adding own compilation command, and why is it inconsistent\n> with the git-%$X's one?\n\nAlthough I'd prefer the simplicity of putting srvside-ssh.o in\nLIB_OBJS, this is arguably defensible; it avoids relinking of\neverything else merely because srvside-ssh.c is changed.\n"},{"id":"10496","messageId":"7v1x2cyplw.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"435B5AE0.1060400@op5.se","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T19:56:11Z","receivedAt":"2005-10-23T19:56:11Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> Junio C Hamano wrote:\n>> Andreas Ericsson <ae@op5.se> writes:\n>> ...\n>> At one point, Linus posted an outline of \"restricted login shell\n>> for use with git over ssh\".  I think you could start from there,\n>> perhaps extend it so that it checks the binaries *and* pathnames\n>> the user can specify (e.g. only under your own $HOME is allowed,\n>> and no /../ in them, or something silly like that).\n>>\n>\n> I found this in the archives:\n> http://article.gmane.org/gmane.comp.version-control.git/5784/match=restricted+login\n>\n> Is that what you're referring to?\n\nNo, it is this one:\n\n    http://marc.theaimsgroup.com/?l=git&m=112681457828137&w=2\n\nBut it is orthogonal to what you are doing in this patch.\n\n> Let me know if you want things done differently.\n\nI think srvside_chdir() should not do the userdir expansion\nunder --strict (otherwise you would need a matching change in\ndaemon.c as well, but I would rather not).\n\nThe --strict flag in upload-pack is to make sure git-daemon can\nsee what is being accessed and make its policy decision even\nbefore it calls upload-pack.  In a pathological case, somebody\ncan create a directory \"/~foo/bar/.git\", where the \"/~foo\"\ndirectory is different from \"/home/foo\", and have git-daemon\ncheck that the former is OK and call your upload-pack.  Your\nupload-pack uses srvside_chdir() and exposes /home/foo/bar/.git;\nthis circumvents git-daemon's policy decision, doesn't it?\n\nI also agree with everything Pasky already said.\n\n * In a URL, a colon after hostname means \"port number\n   follows\".  So it was a good intention to make these\n   consistent:\n\n        git fetch ssh://kernel.org:git\n        git fetch kernel.org:git\n\n   it should not be done.  IOW, if I wanted to use the former\n   form (which I do not think I'd use myself), I should say either one\n   of:\n\n        git fetch ssh://kernel.org:~/git\n        git fetch ssh://kernel.org:~junio/git\n\n   Oh, I just noticed you do not handle the former, because you\n   did not have to, but now you need to.\n\n * Use of \"extern const char *__progname\" is questionable.  I\n   could be easily talked into:\n\n    - have \"extern const char *git_program_name\" in cache.h or\n      somewhere;\n\n    - convert programs (gradually) to set that at the beginning\n      of main();\n\n    - update die() and error() to use that variable when\n      reporting (both callers and implementation) -- this is\n      optional.\n"},{"id":"10497","messageId":"Pine.LNX.4.64.0510231427230.10477@g5.osdl.org","threadId":"2191","inReplyTo":"7v1x2cyplw.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-23T21:30:45Z","receivedAt":"2005-10-23T21:30:45Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 23 Oct 2005, Junio C Hamano wrote:\n> \n> No, it is this one:\n> \n>     http://marc.theaimsgroup.com/?l=git&m=112681457828137&w=2\n> \n> But it is orthogonal to what you are doing in this patch.\n\nWell, not necessarily.\n\nIt's quite arguable that sanity testing might be per-user and could be \ndone by the shell. I'm not at all sure that srvside_chdir() should do any \nextra testing: if you have real ssh access, the user has the right to do \nanything he damn well pleases.\n\nSo it's quite possible that you should do testing in the thing that \nreceives the request, ie in a restricted shell (or, as we already do, in \ngit-daemon).\n\nI tried to find my original unquote example and stupid shell, but \ncouldn't.  So I wrote something untested as usual.\n\nIt's incomplete and almost certainly buggy and generally broken, but \nhere's somethign that you _could_ install as \"git-shell\", and then put \nthat as somebodys shell in /etc/passwd, and it's a start. A very rough \nstart.\n\nSomebody else gets to test it out ;)\n\n\t\tLinus\n\n---\n2906a25bbd1dedbd6bab9ed984a503340229b020\ndiff --git a/Makefile b/Makefile\nindex 7eacf61..34bbdb6 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -102,7 +102,7 @@ SCRIPT_PYTHON = \\\n # The ones that do not have to link with lcrypto nor lz.\n SIMPLE_PROGRAMS = \\\n \tgit-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \\\n-\tgit-stripspace$X git-var$X git-daemon$X\n+\tgit-stripspace$X git-var$X git-daemon$X git-shell$X\n \n # ... and all the rest\n PROGRAMS = \\\ndiff --git a/shell.c b/shell.c\nnew file mode 100644\nindex 0000000..676d398\n--- /dev/null\n+++ b/shell.c\n@@ -0,0 +1,89 @@\n+#include \"cache.h\"\n+\n+static char *dequote(char *arg)\n+{\n+\tchar *dst = arg;\n+\tchar *src = arg;\n+\tchar c;\n+\n+\tif (*src != '\\'')\n+\t\treturn NULL;\n+\tfor (;;) {\n+\t\tc = *++src;\n+\t\tif (!c)\n+\t\t\treturn NULL;\n+\t\tif (c != '\\'') {\n+\t\t\t*dst++ = c;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tswitch (*++src) {\n+\t\tcase '\\0':\n+\t\t\t*dst = 0;\n+\t\t\treturn arg;\n+\t\tcase '\\\\':\n+\t\t\tif (*++src == '\\'' &&\n+\t\t\t    *++src == '\\'') {\n+\t\t\t\t*dst = '\\'';\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t/* Fallthrough */\n+\t\tdefault:\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+}\n+\n+static int do_receive_pack(char *arg)\n+{\n+\tchar cwd[1000];\n+\tchar *my_argv[4];\n+\n+\targ = dequote(arg);\n+\tif (!arg)\t\n+\t\tdie(\"bad argument\");\n+\n+\tmy_argv[0] = \"git-receive-pack\";\n+\tmy_argv[1] = arg;\n+\tmy_argv[2] = NULL;\n+\treturn execvp(\"git-receive-pack\", my_argv);\n+}\n+\n+static struct commands {\n+\tconst char *name;\n+\tint (*exec)(char *arg);\n+} cmd_list[] = {\n+\t{ \"git-receive-pack\", do_receive_pack },\n+\t{ NULL },\n+};\n+\n+int main(int argc, char **argv)\n+{\n+\tchar *prog;\n+\tstruct commands *cmd;\n+\n+\t/* We want to see \"-c cmd args\", and nothing else */\n+\tif (argc != 3 || strcmp(argv[1], \"-c\"))\n+\t\tdie(\"What do you think I am? A shell?\");\n+\tprog = argv[2];\n+\targv += 2;\n+\targc -= 2;\n+\tfor (cmd = cmd_list ; cmd->name ; cmd++) {\n+\t\tint len = strlen(cmd->name);\n+\t\tchar *arg;\n+\t\tif (strncmp(cmd->name, prog, len))\n+\t\t\tcontinue;\n+\t\targ = NULL;\n+\t\tswitch (prog[len]) {\n+\t\tcase '\\0':\n+\t\t\targ = NULL;\n+\t\t\tbreak;\n+\t\tcase ' ':\n+\t\t\targ = prog + len + 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tcontinue;\n+\t\t}\n+\t\texit(cmd->exec(arg));\n+\t}\n+\tdie(\"unrecognized command '%s'\", prog);\n+}\n"},{"id":"10498","messageId":"20051023222554.GT30889@pasky.or.cz","threadId":"2191","inReplyTo":"7voe5gypvi.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-10-23T22:25:54Z","receivedAt":"2005-10-23T22:25:54Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Sun, Oct 23, 2005 at 09:50:25PM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> told me that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> >> diff --git a/Makefile b/Makefile\n> >> index 903c57c..87188ea 100644\n> >> --- a/Makefile\n> >> +++ b/Makefile\n> >> @@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n> >>  %.o: %.S\n> >>  \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n> >>  \n> >> +$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n> >> +\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n> >> +\n> >>  git-%$X: %.o $(LIB_FILE)\n> >>  \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n> >>  \n> >\n> > Why are you adding own compilation command, and why is it inconsistent\n> > with the git-%$X's one?\n> \n> Although I'd prefer the simplicity of putting srvside-ssh.o in\n> LIB_OBJS, this is arguably defensible; it avoids relinking of\n> everything else merely because srvside-ssh.c is changed.\n\nI'm talking only about the compilation command, not about the dependency\nline.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"10499","messageId":"7vveznyih4.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"20051023222554.GT30889@pasky.or.cz","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T22:30:15Z","receivedAt":"2005-10-23T22:30:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> I'm talking only about the compilation command, not about the dependency\n> line.\n\nAh, I missed that typo.  Thanks.\n"},{"id":"10504","messageId":"7vd5lvx2n5.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231427230.10477@g5.osdl.org","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T22:57:34Z","receivedAt":"2005-10-23T22:57:34Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n>> But it is orthogonal to what you are doing in this patch.\n>\n> Well, not necessarily.\n>\n> It's quite arguable that sanity testing might be per-user and could be \n> done by the shell. I'm not at all sure that srvside_chdir() should do any \n> extra testing: if you have real ssh access, the user has the right to do \n> anything he damn well pleases.\n\nThe point of the patch, unless I am mistaken, is to add ~user/\nexpansion to the pathname grokking, so that a remote user does\nnot have to know exactly where on the server each user's home\ndirectory is.\n\nI agree 100% with you that srvside_chdir() is not the place to\ndo policy checking.  In order to avoid the aliasing problem\n(which motivated HPA to add --strict option), the receiving end,\nbe it git-daemon driving upload-pack or git-shell driving\nreceive-pack or upload-pack, can do ~user/ expansion first, then\nrun their policy checking on the canonicalized path before\nspawning the lower level programs using the already\ncanonicalized path.\n\nTo also support the case where upload-pack and receive-pack are\nstarted directly from the ssh connection, these programs need to\napply ~user/ expansion to the incoming path themselves by\ndefault.  In order to avoid double expansion, git-daemon and\ngit-shell should pass --no-user-expansion flag to the lower\nlevel programs when it starts them if we do this.\n\nA common library that takes the path supplied from the other end\nand does ~user/ expansion would be useful for the above; we can\nlift that logic from Andreas' srvside_chdir().\n"},{"id":"10505","messageId":"7v8xwjx2f9.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231427230.10477@g5.osdl.org","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-23T23:02:18Z","receivedAt":"2005-10-23T23:02:18Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> It's incomplete and almost certainly buggy and generally broken, but \n> here's somethign that you _could_ install as \"git-shell\", and then put \n> that as somebodys shell in /etc/passwd, and it's a start. A very rough \n> start.\n>\n> Somebody else gets to test it out ;)\n>\n> +\t\tif (c != '\\'') {\n> +\t\t\t*dst++ = c;\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tswitch (*++src) {\n> +\t\tcase '\\0':\n> +\t\t\t*dst = 0;\n> +\t\t\treturn arg;\n> +\t\tcase '\\\\':\n> +\t\t\tif (*++src == '\\'' &&\n> +\t\t\t    *++src == '\\'') {\n> +\t\t\t\t*dst = '\\'';\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\t\t/* Fallthrough */\n> +\t\tdefault:\n\nI think this misses HPA's addition to minimally suppport csh\nbraindamage (bang bang).\n"},{"id":"10506","messageId":"7vhdb7vk64.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231427230.10477@g5.osdl.org","subject":"[PATCH] Add git-shell.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-24T00:21:55Z","receivedAt":"2005-10-24T00:21:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This adds a very git specific restricted shell, that can be\nadded to /etc/shells and set to the pw_shell in the /etc/passwd\nfile, to give users ability to push into repositories over ssh\nwithout giving them full interactive shell acount.\n\n[jc: I updated Linus' patch to match what the current sq_quote()\n does.]\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n   This one has the '!' dequoting I mentioned earlier, and\n   actually has been tested twice.\n\n   The system administrator should set things up so that the\n   system default PATH environment variable lets users run the\n   supported commands.\n\n   We currently rely on the user to have a full shell access for\n   repository administrative actions (e.g. git-init-db to create\n   a repository, git-repack, and hooks management).  Probably\n   some of them may need to become accessible from git-shell,\n   but I do not know which ones offhand:\n\n   - Creating a repository.  Probably wherever the user has\n     write privilege, or maybe only under the home directory --\n     the policy would be up to the system administrator, with\n     usual filesystem quota applied.\n\n   - I think setting up hooks should be forbidden -- the user\n     can execute arbitrary commands if we allowed it.  Instead,\n     the administrator can set things up for people, and would\n     probably make creative use of hooks/update to implement\n     access control (e.g. forbidding non-fast-forward pushes).\n\n   - Similarly, packing can be left to hooks/post-update or cron\n     job, either of which is under administrator control.\n\n Makefile |    2 +-\n quote.c  |   41 ++++++++++++++++++++++++++++++++++++++++-\n quote.h  |    6 ++++++\n shell.c  |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 106 insertions(+), 2 deletions(-)\n create mode 100644 shell.c\n\napplies-to: c043f0993afe5c057409ef748ce313c89c20c7dc\nf176536e2cd5949fa134d8b24dc07dd1f0744b6f\ndiff --git a/Makefile b/Makefile\nindex 5bdf3cc..5b0306d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -116,7 +116,7 @@ PROGRAMS = \\\n \tgit-merge-index$X git-mktag$X git-pack-objects$X git-patch-id$X \\\n \tgit-peek-remote$X git-prune-packed$X git-read-tree$X \\\n \tgit-receive-pack$X git-rev-list$X git-rev-parse$X \\\n-\tgit-send-pack$X git-show-branch$X \\\n+\tgit-send-pack$X git-show-branch$X git-shell$X \\\n \tgit-show-index$X git-ssh-fetch$X \\\n \tgit-ssh-upload$X git-tar-tree$X git-unpack-file$X \\\n \tgit-unpack-objects$X git-update-index$X git-update-server-info$X \\\ndiff --git a/quote.c b/quote.c\nindex 009e694..e662a7d 100644\n--- a/quote.c\n+++ b/quote.c\n@@ -15,6 +15,11 @@\n #undef EMIT\n #define EMIT(x) ( (++len < n) && (*bp++ = (x)) )\n \n+static inline int need_bs_quote(char c)\n+{\n+\treturn (c == '\\'' || c == '!');\n+}\n+\n size_t sq_quote_buf(char *dst, size_t n, const char *src)\n {\n \tchar c;\n@@ -23,7 +28,7 @@ size_t sq_quote_buf(char *dst, size_t n,\n \n \tEMIT('\\'');\n \twhile ((c = *src++)) {\n-\t\tif (c == '\\'' || c == '!') {\n+\t\tif (need_bs_quote(c)) {\n \t\t\tEMIT('\\'');\n \t\t\tEMIT('\\\\');\n \t\t\tEMIT(c);\n@@ -52,6 +57,40 @@ char *sq_quote(const char *src)\n \treturn buf;\n }\n \n+char *sq_dequote(char *arg)\n+{\n+\tchar *dst = arg;\n+\tchar *src = arg;\n+\tchar c;\n+\n+\tif (*src != '\\'')\n+\t\treturn NULL;\n+\tfor (;;) {\n+\t\tc = *++src;\n+\t\tif (!c)\n+\t\t\treturn NULL;\n+\t\tif (c != '\\'') {\n+\t\t\t*dst++ = c;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* We stepped out of sq */\n+\t\tswitch (*++src) {\n+\t\tcase '\\0':\n+\t\t\t*dst = 0;\n+\t\t\treturn arg;\n+\t\tcase '\\\\':\n+\t\t\tc = *++src;\n+\t\t\tif (need_bs_quote(c) && *++src == '\\'') {\n+\t\t\t\t*dst++ = c;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t/* Fallthrough */\n+\t\tdefault:\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+}\n+\n /*\n  * C-style name quoting.\n  *\ndiff --git a/quote.h b/quote.h\nindex 2fdde3b..2486e6e 100644\n--- a/quote.h\n+++ b/quote.h\n@@ -31,6 +31,12 @@\n extern char *sq_quote(const char *src);\n extern size_t sq_quote_buf(char *dst, size_t n, const char *src);\n \n+/* This unwraps what sq_quote() produces in place, but returns\n+ * NULL if the input does not look like what sq_quote would have\n+ * produced.\n+ */\n+extern char *sq_dequote(char *);\n+\n extern int quote_c_style(const char *name, char *outbuf, FILE *outfp,\n \t\t\t int nodq);\n extern char *unquote_c_style(const char *quoted, const char **endp);\ndiff --git a/shell.c b/shell.c\nnew file mode 100644\nindex 0000000..2c4789e\n--- /dev/null\n+++ b/shell.c\n@@ -0,0 +1,59 @@\n+#include \"cache.h\"\n+#include \"quote.h\"\n+\n+static int do_generic_cmd(const char *me, char *arg)\n+{\n+\tconst char *my_argv[4];\n+\n+\targ = sq_dequote(arg);\n+\tif (!arg)\n+\t\tdie(\"bad argument\");\n+\n+\tmy_argv[0] = me;\n+\tmy_argv[1] = arg;\n+\tmy_argv[2] = NULL;\n+\n+\treturn execvp(me, (char**) my_argv);\n+}\n+\n+static struct commands {\n+\tconst char *name;\n+\tint (*exec)(const char *me, char *arg);\n+} cmd_list[] = {\n+\t{ \"git-receive-pack\", do_generic_cmd },\n+\t{ \"git-upload-pack\", do_generic_cmd },\n+\t{ NULL },\n+};\n+\n+int main(int argc, char **argv)\n+{\n+\tchar *prog;\n+\tstruct commands *cmd;\n+\n+\t/* We want to see \"-c cmd args\", and nothing else */\n+\tif (argc != 3 || strcmp(argv[1], \"-c\"))\n+\t\tdie(\"What do you think I am? A shell?\");\n+\n+\tprog = argv[2];\n+\targv += 2;\n+\targc -= 2;\n+\tfor (cmd = cmd_list ; cmd->name ; cmd++) {\n+\t\tint len = strlen(cmd->name);\n+\t\tchar *arg;\n+\t\tif (strncmp(cmd->name, prog, len))\n+\t\t\tcontinue;\n+\t\targ = NULL;\n+\t\tswitch (prog[len]) {\n+\t\tcase '\\0':\n+\t\t\targ = NULL;\n+\t\t\tbreak;\n+\t\tcase ' ':\n+\t\t\targ = prog + len + 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tcontinue;\n+\t\t}\n+\t\texit(cmd->exec(cmd->name, arg));\n+\t}\n+\tdie(\"unrecognized command '%s'\", prog);\n+}\n---\n0.99.8.GIT\n"},{"id":"10507","messageId":"Pine.LNX.4.64.0510231751040.10477@g5.osdl.org","threadId":"2191","inReplyTo":"7vhdb7vk64.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-shell.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-24T00:52:49Z","receivedAt":"2005-10-24T00:52:49Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 23 Oct 2005, Junio C Hamano wrote:\n>\n> This adds a very git specific restricted shell, that can be\n> added to /etc/shells and set to the pw_shell in the /etc/passwd\n> file, to give users ability to push into repositories over ssh\n> without giving them full interactive shell acount.\n\nDid you actually test that it works as somebody's login-shell and can be \nused for pushing?\n\nI think it should add \"pull\" functionality too, so that you can have \nrestricted reading (hey, git may be open source, but not everything that \nis maintained in it necessarily will be..)\n\n\t\t\tLinus\n"},{"id":"10508","messageId":"Pine.LNX.4.64.0510231754130.10477@g5.osdl.org","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231751040.10477@g5.osdl.org","subject":"Re: [PATCH] Add git-shell.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-24T00:55:05Z","receivedAt":"2005-10-24T00:55:05Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 23 Oct 2005, Linus Torvalds wrote:\n> \n> Did you actually test that it works as somebody's login-shell and can be \n> used for pushing?\n> \n> I think it should add \"pull\" functionality too\n\nGaah, I only read your description, didn't look closer at the patch. The \ndescription just said \"push\", but you added the pull side too, and \napparently even tested it. Goodie.\n\nNever mind me.\n\n\t\t\tLinus\n"},{"id":"10510","messageId":"435C3427.30803@zytor.com","threadId":"2191","inReplyTo":"7v8xwjx2f9.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-24T01:08:55Z","receivedAt":"2005-10-24T01:08:55Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> \n>>It's incomplete and almost certainly buggy and generally broken, but \n>>here's somethign that you _could_ install as \"git-shell\", and then put \n>>that as somebodys shell in /etc/passwd, and it's a start. A very rough \n>>start.\n>>\n>>Somebody else gets to test it out ;)\n>>\n>>+\t\tif (c != '\\'') {\n>>+\t\t\t*dst++ = c;\n>>+\t\t\tcontinue;\n>>+\t\t}\n>>+\t\tswitch (*++src) {\n>>+\t\tcase '\\0':\n>>+\t\t\t*dst = 0;\n>>+\t\t\treturn arg;\n>>+\t\tcase '\\\\':\n>>+\t\t\tif (*++src == '\\'' &&\n>>+\t\t\t    *++src == '\\'') {\n>>+\t\t\t\t*dst = '\\'';\n>>+\t\t\t\tcontinue;\n>>+\t\t\t}\n>>+\t\t/* Fallthrough */\n>>+\t\tdefault:\n> \n> I think this misses HPA's addition to minimally suppport csh\n> braindamage (bang bang).\n> \n\nIf this is meant to dequote shell-quoted paths, it really should be modal.\n\n\t-hpa\n"},{"id":"10512","messageId":"7vek6bu24o.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231751040.10477@g5.osdl.org","subject":"Re: [PATCH] Add git-shell.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-24T01:36:55Z","receivedAt":"2005-10-24T01:36:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Sun, 23 Oct 2005, Junio C Hamano wrote:\n>>\n>> This adds a very git specific restricted shell, that can be\n>> added to /etc/shells and set to the pw_shell in the /etc/passwd\n>> file, to give users ability to push into repositories over ssh\n>> without giving them full interactive shell acount.\n>\n> Did you actually test that it works as somebody's login-shell and can be \n> used for pushing?\n\nI made a temporary user on my notebook, set it as his login\nshell, and run peek-remote against it (which means the git-shell\nspawned upload-pack on the other end).  No, I did not try pushing\nwhen I sent the patch\n\nBut I just did, and it seems to work, so this should hit the\nmaster branch soon ;-).\n"},{"id":"10513","messageId":"Pine.LNX.4.64.0510231836020.10477@g5.osdl.org","threadId":"2191","inReplyTo":"435C3427.30803@zytor.com","subject":"Re: User-relative paths","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-24T01:37:12Z","receivedAt":"2005-10-24T01:37:12Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 23 Oct 2005, H. Peter Anvin wrote:\n> \n> If this is meant to dequote shell-quoted paths, it really should be modal.\n\nIt _only_ accepts quoted strings, so it \"is\" modal. It has one mode: \nstring. And it's a bitch about enforcing it, too (it just dies if it \nwasn't one).\n\n\t\tLinus\n"},{"id":"10514","messageId":"435C3C6D.7000201@zytor.com","threadId":"2191","inReplyTo":"Pine.LNX.4.64.0510231836020.10477@g5.osdl.org","subject":"Re: User-relative paths","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-24T01:44:13Z","receivedAt":"2005-10-24T01:44:13Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Linus Torvalds wrote:\n> \n> On Sun, 23 Oct 2005, H. Peter Anvin wrote:\n> \n>>If this is meant to dequote shell-quoted paths, it really should be modal.\n> \n> It _only_ accepts quoted strings, so it \"is\" modal. It has one mode: \n> string. And it's a bitch about enforcing it, too (it just dies if it \n> wasn't one).\n> \n\nThat wasn't what I meant.  '...' is a modal escape in the shell.  Thus, \nsomething like this which actually mimics the state machine, at least \nfor the potential characters we care about.\n\n\n#define EMIT(x) { ( ++len < n ) && *dst++ = (x) )\n\nint unquote(char *dst, size_t n, const char *src)\n{\n\tenum state st = { st_zero, st_quote, st_escape };\n\tint len = 0;\n\tchar c;\n\t\n\twhile ( (c = *src++) ) {\n\t\tswitch ( st ) {\n\t\tcase st_zero:\n\t\t\tif ( c == '\\'' )\n\t\t\t\tst = st_quote;\n\t\t\telse if ( c == '\\\\' )\n\t\t\t\tst = st_escape;\n\t\t\telse\n\t\t\t\tEMIT(c);\n\t\t\tbreak;\n\t\t\t\n\t\tcase st_quote:\n\t\t\tif ( c == '\\'' )\n\t\t\t\tst = st_zero;\n\t\t\telse\n\t\t\t\tEMIT(c);\n\t\t\tbreak;\n\t\t\t\n\t\tcase st_escape:\n\t\t\tEMIT(c);\n\t\t\tst = st_zero;\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tif ( n )\n\t\t*dst = 0;\n\t\n\treturn (st == st_zero) ? len : -1;\n}\n"},{"id":"10516","messageId":"7vslursmnc.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"435C3427.30803@zytor.com","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-24T01:56:39Z","receivedAt":"2005-10-24T01:56:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"H. Peter Anvin\" <hpa@zytor.com> writes:\n\n> If this is meant to dequote shell-quoted paths, it really should be modal.\n\nYou are right, but this is not meant to dequote arbitrary shell\nquoted paths.  It specifically is for unwrapping what sq_quote()\nproduced, and refuses to proceed if you feed some shell-valid\nbut not sq_quote() produced string.  The reason is because it is\npart of the git-shell \"login shell\" -- the input validation is\nenforced there.\n\nAnd the reason it lives next to quote.c::sq_quote() is that you\nwould hopefully notice sq_dequote() needs matching changes when\nyou ever update sq_quote.\n"},{"id":"10517","messageId":"7voe5fsm3w.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"7v1x2cyplw.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-24T02:08:19Z","receivedAt":"2005-10-24T02:08:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n>  * In a URL, a colon after hostname means \"port number\n>    follows\".  So it was a good intention to make these\n>    consistent:\n>\n>         git fetch ssh://kernel.org:git\n>         git fetch kernel.org:git\n>\n>    it should not be done.  IOW, if I wanted to use the former\n>    form (which I do not think I'd use myself), I should say either one\n>    of:\n>\n>         git fetch ssh://kernel.org:~/git\n>         git fetch ssh://kernel.org:~junio/git\n>\n>    Oh, I just noticed you do not handle the former, because you\n>    did not have to, but now you need to.\n\nThe \"should be this way\" examples should have been something\nlike this:\n\n        git fetch ssh://kernel.org/~/git\n        git fetch ssh://kernel.org/~junio/git\n\nOtherwise what I said does not make *any* sense.\n\n          \t Junio \"Oh, I am an idiot\" Hamano\n"},{"id":"10523","messageId":"Pine.LNX.4.64.0510240219410.25300@iabervon.org","threadId":"2191","inReplyTo":"7voe5gypvi.fsf@assigned-by-dhcp.cox.net","subject":"Re: User-relative paths","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-10-24T06:28:04Z","receivedAt":"2005-10-24T06:28:04Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sun, 23 Oct 2005, Junio C Hamano wrote:\n\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> >> diff --git a/Makefile b/Makefile\n> >> index 903c57c..87188ea 100644\n> >> --- a/Makefile\n> >> +++ b/Makefile\n> >> @@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n> >>  %.o: %.S\n> >>  \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n> >>  \n> >> +$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n> >> +\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n> >> +\n> >>  git-%$X: %.o $(LIB_FILE)\n> >>  \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n> >>  \n> >\n> > Why are you adding own compilation command, and why is it inconsistent\n> > with the git-%$X's one?\n> \n> Although I'd prefer the simplicity of putting srvside-ssh.o in\n> LIB_OBJS, this is arguably defensible; it avoids relinking of\n> everything else merely because srvside-ssh.c is changed.\n\nThe line:\n\n$(SERVERSIDE_PROGRAMS): srvside-ssh.o\n\nwould suffice for that.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"10562","messageId":"435DE309.9090509@op5.se","threadId":"2191","inReplyTo":"20051023183757.GS30889@pasky.or.cz","subject":"Re: User-relative paths","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-25T07:47:21Z","receivedAt":"2005-10-25T07:47:21Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Petr Baudis wrote:\n> Dear diary, on Sun, Oct 23, 2005 at 11:41:52AM CEST, I got a letter\n> where Andreas Ericsson <ae@op5.se> told me that...\n> \n>>Anyways, the attached patch does this. I've tested all the various \n>>syntaxes and they work as expected. rsync, http and local files take the \n>>same syntax as before. I haven't added support for user-relative paths \n>>to the git-daemon (can't see the point, really) although that can be \n>>done easily enough.\n> \n> \n> It would be useful to add a [PATCH] tag to subject when you submit a\n> patch, so that we notice it better. ;-)\n> \n\nWill do in the future. I thought it was auto-imported for buildtest if \nit was.\n\n> You don't update the documentation even though there seem to be some\n> syntactic changes. You should at least update\n> \n> \tDocumentation/pull-fetch-param.txt\n> \n\nTrue. I'll need to re-work the patch a bit to take Junio's RFC on paths \ninto account. I'll do this then.\n\n> Also before Junio asks you, in the followup patches, you might want to\n> sign off the patch if you want it integrated.\n> \n> \n>>diff --git a/Makefile b/Makefile\n>>index 903c57c..87188ea 100644\n>>--- a/Makefile\n>>+++ b/Makefile\n>>@@ -359,6 +362,9 @@ git-cherry-pick: git-revert\n>> %.o: %.S\n>> \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n>> \n>>+$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)\n>>+\t$(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)\n>>+\n>> git-%$X: %.o $(LIB_FILE)\n>> \t$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)\n>> \n> \n> \n> Why are you adding own compilation command, and why is it inconsistent\n> with the git-%$X's one?\n> \n\nMainly because I'm really no good at Makefiles and just noticed that \nthis seems to do what I want. My own projects rarely stretch over 15 \nfiles and it's usually just one or two binaries, so I haven't gotten \nround to learning the finer points of make.\n\n> \n>>diff --git a/connect.c b/connect.c\n>>index b171c5d..0d78b3e 100644\n>>--- a/connect.c\n>>+++ b/connect.c\n>>@@ -436,33 +436,44 @@ static int git_tcp_connect(int fd[2], co\n>>+\t/* leading colon marks relative path for ssh.\n>>+\t * Check for host == url and default to PROTO_SSH to allow\n>>+\t *   $ git fetch kernel.org:git\n>>+\t */\n>>+\tif(ptr && (!path || ptr < path)) {\n>>+\t\tif(host == url)\n>>+\t\t\tprotocol = PROTO_SSH;\n>>+\n>>+\t\tif(protocol == PROTO_SSH) {\n>>+\t\t\t*ptr = '\\0';\n>>+\t\t\tpath = ptr + 1;\n>> \t\t}\n>> \t}\n> \n> \n> If I understand this right,\n> \n> \tssh://foo.bar:baz/quux\n> \n> will make foo.bar the host and baz/quux the path. Please, do NOT do\n> this! It is supposed to be a URL, dammit! And you know, URLs have\n> defined _syntax_, and that's important at least every time the URL gets\n> out of GIT's context. Or stop it calling URL altogether, to prevent any\n> confusion. But in URLs, the space between : and / is a port definition.\n> See also RFC3986 (aka STD066) and RFC2718.\n> \n> Thanks.\n> \n\nRight you are. I was thinking scp like syntax rather than url.\n\n> \n>>diff --git a/receive-pack.c b/receive-pack.c\n>>index 8f157bc..9a040ff 100644\n>>--- a/receive-pack.c\n>>+++ b/receive-pack.c\n>>@@ -265,18 +267,9 @@ int main(int argc, char **argv)\n>> \tif (!dir)\n>> \t\tusage(receive_pack_usage);\n>> \n>>-\t/* chdir to the directory. If that fails, try appending \".git\" */\n>>-\tif (chdir(dir) < 0) {\n>>-\t\tif (chdir(mkpath(\"%s.git\", dir)) < 0)\n>>-\t\t\tdie(\"unable to cd to %s\", dir);\n>>-\t}\n>>-\n>>-\t/* If we have a \".git\" directory, chdir to it */\n>>-\tchdir(\".git\");\n>>-\tputenv(\"GIT_DIR=.\");\n>>+\t/* Find the right directory */\n>>+\tsrvside_chdir(dir, 0);\n>> \n>>-\tif (access(\"objects\", X_OK) < 0 || access(\"refs/heads\", X_OK) < 0)\n>>-\t\tdie(\"%s doesn't appear to be a git directory\", dir);\n>> \twrite_head_info();\n>> \n>> \t/* EOF */\n> \n> \n> No srvside_chdir() declaration?\n> \n> \n>>diff --git a/srvside-ssh.c b/srvside-ssh.c\n>>new file mode 100644\n>>index 0000000..0ed5d30\n>>--- /dev/null\n>>+++ b/srvside-ssh.c\n>>@@ -0,0 +1,63 @@\n>>+#include \"cache.h\"\n>>+#include <unistd.h>\n>>+#include <pwd.h>\n>>+\n>>+extern const char *__progname;\n> \n> \n> How portable is this? It appears that no standard really defines this,\n> and Google faintly hints at least some Cygwin-related problems...\n> \n\nSomewhat, but not very. It was more of a quick hack since the old code \nhad hardcoded program names. If this gets supported in git-daemon as \nwell it should say \"git-daemon\" in the error message, so I think either \npass it as a parameter or invent some git_progname variable and use some \nsmall init-code for all programs.\n\n> \n>>diff --git a/upload-pack.c b/upload-pack.c\n>>index accdba6..356c9b1 100644\n>>--- a/upload-pack.c\n>>+++ b/upload-pack.c\n>>@@ -5,6 +5,7 @@\n>> #include \"object.h\"\n>> \n>> static const char upload_pack_usage[] = \"git-upload-pack [--strict] [--timeout=nn] <dir>\";\n>>+extern void srvside_chdir(const char *path, int strict);\n>> \n>> #define MAX_HAS 256\n>> #define MAX_NEEDS 256\n> \n> \n> What about a .h file?\n> \n\nPrototype patch, sort of, and since it's only one function I thought \nit'd be better to keep it as unobtrusive as possible.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"10568","messageId":"435DF6DA.6010205@op5.se","threadId":"2191","inReplyTo":"7v1x2cyplw.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git_progname (was: Re: User-relative paths)","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-25T09:11:54Z","receivedAt":"2005-10-25T09:11:54Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Andreas Ericsson <ae@op5.se> writes:\n> \n> \n>>Junio C Hamano wrote:\n>>\n>>>Andreas Ericsson <ae@op5.se> writes:\n>>>...\n>>>At one point, Linus posted an outline of \"restricted login shell\n>>>for use with git over ssh\".  I think you could start from there,\n>>>perhaps extend it so that it checks the binaries *and* pathnames\n>>>the user can specify (e.g. only under your own $HOME is allowed,\n>>>and no /../ in them, or something silly like that).\n>>>\n>>\n>>I found this in the archives:\n>>http://article.gmane.org/gmane.comp.version-control.git/5784/match=restricted+login\n>>\n>>Is that what you're referring to?\n> \n> \n> No, it is this one:\n> \n>     http://marc.theaimsgroup.com/?l=git&m=112681457828137&w=2\n> \n> But it is orthogonal to what you are doing in this patch.\n> \n> \n>>Let me know if you want things done differently.\n> \n> \n> I think srvside_chdir() should not do the userdir expansion\n> under --strict (otherwise you would need a matching change in\n> daemon.c as well, but I would rather not).\n> \n\nTrue. I'll rework it.\n\n> The --strict flag in upload-pack is to make sure git-daemon can\n> see what is being accessed and make its policy decision even\n> before it calls upload-pack.  In a pathological case, somebody\n> can create a directory \"/~foo/bar/.git\", where the \"/~foo\"\n> directory is different from \"/home/foo\", and have git-daemon\n> check that the former is OK and call your upload-pack.  Your\n> upload-pack uses srvside_chdir() and exposes /home/foo/bar/.git;\n\n\nIt shouldn't, because srvside_chdir() will only user-expand paths that \nstart with a tilde.\n\n\n> this circumvents git-daemon's policy decision, doesn't it?\n> \n> I also agree with everything Pasky already said.\n> \n>  * In a URL, a colon after hostname means \"port number\n>    follows\".  So it was a good intention to make these\n>    consistent:\n> \n>         git fetch ssh://kernel.org:git\n>         git fetch kernel.org:git\n> \n>    it should not be done.  IOW, if I wanted to use the former\n>    form (which I do not think I'd use myself), I should say either one\n>    of:\n> \n>         git fetch ssh://kernel.org:~/git\n>         git fetch ssh://kernel.org:~junio/git\n> \n>    Oh, I just noticed you do not handle the former, because you\n>    did not have to, but now you need to.\n> \n>  * Use of \"extern const char *__progname\" is questionable.  I\n>    could be easily talked into:\n> \n>     - have \"extern const char *git_program_name\" in cache.h or\n>       somewhere;\n> \n>     - convert programs (gradually) to set that at the beginning\n>       of main();\n> \n\nSee the attached patch, which adds git_progname as a global variable to \ndaemon.c with a minimum of fuzz. The one-liner below will add it to the \nrest of the programs. GNU sed >= 4.0.9 required.\n\ngrep -l \"int main\" *.c | xargs -- sed -i '/^#include/i#include \"main.h\"'\n\n>     - update die() and error() to use that variable when\n>       reporting (both callers and implementation) -- this is\n>       optional.\n> \n> \n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\n\ndiff --git a/Makefile b/Makefile\nindex 5b0306d..f8e4511 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -147,7 +147,7 @@ LIB_FILE=libgit.a\n LIB_H = \\\n \tblob.h cache.h commit.h count-delta.h csum-file.h delta.h \\\n \tdiff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \\\n-\trun-command.h strbuf.h tag.h tree.h\n+\trun-command.h strbuf.h tag.h tree.h main.h\n \n DIFF_OBJS = \\\n \tdiff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \\\ndiff --git a/cache.h b/cache.h\nindex d776016..db5d667 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -45,6 +45,13 @@\n #endif\n #endif\n \n+#if defined(__GLIBC__)\n+extern const char *__progname;\n+#define git_progname __progname\n+#else\n+extern const char *git_progname;\n+#endif\n+\n /*\n  * Intensive research over the course of many years has shown that\n  * port 9418 is totally unused by anything else. Or\ndiff --git a/daemon.c b/daemon.c\nindex 0c6182f..c197ee5 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,3 +1,4 @@\n+#include \"main.h\"\n #include \"cache.h\"\n #include \"pkt-line.h\"\n #include <signal.h>\ndiff --git a/main.h b/main.h\nnew file mode 100644\nindex 0000000..472f134\n--- /dev/null\n+++ b/main.h\n@@ -0,0 +1,22 @@\n+/* unistd.h must be available and the glibc version includes features.h\n+ * from it which #defines __GLIBC__ and friends */\n+#include <unistd.h>\n+#ifndef __GLIBC__\n+const char *git_progname;\n+static int git_main(int, char **);\n+\n+int main(int argc, char **argv)\n+{\n+\tchar *p;\n+\tgit_progname = p = *argv;\n+\n+\t/* don't use any library functions. We won't have the headers */\n+\twhile(*p)\n+\t\tif(*p++ == '/')\n+\t\t\tgit_progname = p;\n+\n+\treturn git_main(argc, argv);\n+}\n+\n+#define main(argc, argv) git_main(argc, argv)\n+#endif /* __GLIBC__ */\n"},{"id":"10570","messageId":"20051025093150.GB30889@pasky.or.cz","threadId":"2191","inReplyTo":"435DF6DA.6010205@op5.se","subject":"Re: [PATCH] git_progname (was: Re: User-relative paths)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-10-25T09:31:50Z","receivedAt":"2005-10-25T09:31:50Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Could you please also trim the mails you are replying to a bit?\n\nDear diary, on Tue, Oct 25, 2005 at 11:11:54AM CEST, I got a letter\nwhere Andreas Ericsson <ae@op5.se> told me that...\n> See the attached patch, which adds git_progname as a global variable to \n> daemon.c with a minimum of fuzz. The one-liner below will add it to the \n> rest of the programs. GNU sed >= 4.0.9 required.\n> \n> grep -l \"int main\" *.c | xargs -- sed -i '/^#include/i#include \"main.h\"'\n\nUrgh. Now this is ugly. What about making it a bit more intrusive while\nquite more saner?\n\n> diff --git a/cache.h b/cache.h\n> index d776016..db5d667 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -45,6 +45,13 @@\n>  #endif\n>  #endif\n>  \n> +#if defined(__GLIBC__)\n> +extern const char *__progname;\n> +#define git_progname __progname\n> +#else\n> +extern const char *git_progname;\n> +#endif\n> +\n>  /*\n>   * Intensive research over the course of many years has shown that\n>   * port 9418 is totally unused by anything else. Or\n\nAlso, when you already solve this for non-__GLIBC__ systems, I doubt\nthat there is any win in keeping the __GLIBC__-specific hack, except\nthat most developers won't see any bugs in the generic solution since\nthey are using glibc.\n\n> diff --git a/main.h b/main.h\n> new file mode 100644\n> index 0000000..472f134\n> --- /dev/null\n> +++ b/main.h\n> @@ -0,0 +1,22 @@\n> +/* unistd.h must be available and the glibc version includes features.h\n> + * from it which #defines __GLIBC__ and friends */\n> +#include <unistd.h>\n> +#ifndef __GLIBC__\n> +const char *git_progname;\n> +static int git_main(int, char **);\n> +\n> +int main(int argc, char **argv)\n> +{\n> +\tchar *p;\n> +\tgit_progname = p = *argv;\n> +\n> +\t/* don't use any library functions. We won't have the headers */\n> +\twhile(*p)\n> +\t\tif(*p++ == '/')\n> +\t\t\tgit_progname = p;\n> +\n> +\treturn git_main(argc, argv);\n> +}\n> +\n> +#define main(argc, argv) git_main(argc, argv)\n> +#endif /* __GLIBC__ */\n\nSomeone said that converting main()s to git_main()s would help the\nlibification effort, but I suspect that you actually want to set the\nprogname to whatever you call when you call its git_main().\n\nWe can make it go into the init section, but that won't be too portable\neither.\n\nSo I'd say just add setup_progname(\"foo\") at the start of your main().\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"10573","messageId":"435E1307.3090209@op5.se","threadId":"2191","inReplyTo":"20051025093150.GB30889@pasky.or.cz","subject":"Re: [PATCH] git_progname","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-25T11:12:07Z","receivedAt":"2005-10-25T11:12:07Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Petr Baudis wrote:\n> Could you please also trim the mails you are replying to a bit?\n> \n\nAye.\n\n> Dear diary, on Tue, Oct 25, 2005 at 11:11:54AM CEST, I got a letter\n> where Andreas Ericsson <ae@op5.se> told me that...\n> \n>>grep -l \"int main\" *.c | xargs -- sed -i '/^#include/i#include \"main.h\"'\n> \n> \n> Urgh. Now this is ugly. What about making it a bit more intrusive while\n> quite more saner?\n> \n\nI'm not sure what you're referring to. The one-liner is a one-liner. \nIt's sort of supposed to be ugly.\n\nIncluding main.h is a fairly sane option for common initialization code.\n\n> \n> Also, when you already solve this for non-__GLIBC__ systems, I doubt\n> that there is any win in keeping the __GLIBC__-specific hack, except\n> that most developers won't see any bugs in the generic solution since\n> they are using glibc.\n> \n\nTrue. I'll rework it if someone thinks it's worth it.\n\n> \n> Someone said that converting main()s to git_main()s would help the\n> libification effort,\n\n\nI had some thoughts along those lines as well, especially for reading \nconfiguration files.\n\n> but I suspect that you actually want to set the\n> progname to whatever you call when you call its git_main().\n> \n\nThis I don't understand. Do you mean \"set the progname to whatever you \ncall\" as in \"set the progname to whatever the program author calls the \nprogram\" or as in \"set the progname to whatever it's called as from the \ncommand-line\"?\n\n> We can make it go into the init section, but that won't be too portable\n> either.\n> \n> So I'd say just add setup_progname(\"foo\") at the start of your main().\n> \n\nSet the progname to whatever the author calls it then.\n\nIf so, I'd put\nconst char *git_progname = GIT_PROGNAME;\nanywhere in the main() file and expanding the %.o: rule to include \n-DGIT_PROGNAME=\\\"git-$*\\\"\n\nThis would bark if there's a program that doesn't have it that's linked \nagainst something that uses it, which the setup_progname() approach \nwouldn't do.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"10576","messageId":"435E2ABA.8030907@op5.se","threadId":"2191","inReplyTo":"435E1307.3090209@op5.se","subject":"Re: [PATCH] git_progname","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2005-10-25T12:53:14Z","receivedAt":"2005-10-25T12:53:14Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Andreas Ericsson wrote:\n> Petr Baudis wrote:\n> \n>>> grep -l \"int main\" *.c | xargs -- sed -i '/^#include/i#include \"main.h\"'\n>>\n>>\n>> Urgh. Now this is ugly. What about making it a bit more intrusive while\n>> quite more saner?\n>>\n> \n> I'm not sure what you're referring to. The one-liner is a one-liner. \n> It's sort of supposed to be ugly.\n> \n\nOh. I saw what you meant now. Lots of main.h included. :)\n\nSilly me. Sorry about that.\n\nI guess some manual editing could be done.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"10578","messageId":"20051025133208.GC30889@pasky.or.cz","threadId":"2191","inReplyTo":"435E2ABA.8030907@op5.se","subject":"Re: [PATCH] git_progname","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-10-25T13:32:08Z","receivedAt":"2005-10-25T13:32:08Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Tue, Oct 25, 2005 at 02:53:14PM CEST, I got a letter\nwhere Andreas Ericsson <ae@op5.se> told me that...\n> Andreas Ericsson wrote:\n> >Petr Baudis wrote:\n> >>Urgh. Now this is ugly. What about making it a bit more intrusive while\n> >>quite more saner?\n> >\n> >I'm not sure what you're referring to. The one-liner is a one-liner. \n> >It's sort of supposed to be ugly.\n> \n> Oh. I saw what you meant now. Lots of main.h included. :)\n\nNo, I didn't mean the oneliner at all, actually - just the notion that\nyou stealthily hijack main(). We'll see what Junio thinks about it. ;)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"10639","messageId":"7v1x28bylq.fsf@assigned-by-dhcp.cox.net","threadId":"2191","inReplyTo":"20051025133208.GC30889@pasky.or.cz","subject":"Re: [PATCH] git_progname","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-26T06:07:13Z","receivedAt":"2005-10-26T06:07:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> No, I didn't mean the oneliner at all, actually - just the notion that\n> you stealthily hijack main(). We'll see what Junio thinks about it. ;)\n\nMay I just say \"yuck\"?\n\nI think what you suggested makes the most sense.\n\n>> So I'd say just add setup_progname(\"foo\") at the start of your main().\n"},{"id":"10693","messageId":"pan.2005.10.27.08.34.11.285742@smurf.noris.de","threadId":"2191","inReplyTo":"20051025093150.GB30889@pasky.or.cz","subject":"Re: [PATCH] git_progname (was: Re: User-relative paths)","fromName":"Matthias Urlichs","fromEmail":"smurf@smurf.noris.de","sentAt":"2005-10-27T08:34:12Z","receivedAt":"2005-10-27T08:34:12Z","isPatch":true,"sender":{"key":"matthias@urlichs.de","avatar":"https://gravatar.com/avatar/2708905af227313eba6f2b2ae0f7d0259b5ac5d71baef58fe5a13c699ce0bbf0?d=mp&s=160"},"body":"Hi, Petr Baudis wrote:\n\n> Someone said that converting main()s to git_main()s would help the\n> libification effort,\n\nWasn't me, and frankly I doubt it. \"old-style\" programs just call the\ncompatibility interface instead, and \"new-style\" ones call the libraries'\ninitialization *after* they've parsed any environment vars or flags \nthat are necessary.\n\n-- \nMatthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de\nDisclaimer: The quote was selected randomly. Really. | http://smurf.noris.de\n - -\nWhile the difficulties and dangers of problems tend to increase at a\ngeometric rate, the knowledge and manpower qualified to deal with these\nproblems tend to increase at an arithmetic rate.\n\t\t\t\t\t-- Yehezkel Dror\n"}]}