commit - 760a1ec3d507da3e46a5dc13041ad1a23cfc0847
commit + 6cc8a118a74d4c7a3f037ad0f755a3aadf5288d6
blob - 3325c8994f55721d8588155cdc72b95d11fd2248
blob + 5f5329cec70be10b102cac79e9dffe3f204c951a
--- lib/dial.c
+++ lib/dial.c
#include <assert.h>
#include <err.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
return err;
}
+/*
+ * Escape a given path for the shell which will be started by sshd.
+ * In particular, git-shell is known to require single-quote characters
+ * around its repository path argument and will refuse to run otherwise.
+ */
+static const struct got_error *
+escape_path(char *buf, size_t bufsize, const char *path)
+{
+ const char *p;
+ char *q;
+
+ p = path;
+ q = buf;
+
+ if (bufsize > 1)
+ *q++ = '\'';
+
+ while (*p != '\0' && (q - buf < bufsize)) {
+ /* git escapes ! too */
+ if (*p != '\'' && *p != '!') {
+ *q++ = *p++;
+ continue;
+ }
+
+ if (q - buf + 4 >= bufsize)
+ break;
+ *q++ = '\'';
+ *q++ = '\\';
+ *q++ = *p++;
+ *q++ = '\'';
+ }
+
+ if (*p == '\0' && (q - buf + 1 < bufsize)) {
+ *q++ = '\'';
+ *q = '\0';
+ return NULL;
+ }
+
+ return got_error_fmt(GOT_ERR_NO_SPACE, "overlong path: %s", path);
+}
+
const struct got_error *
got_dial_ssh(pid_t *newpid, int *newfd, const char *host,
const char *port, const char *path, const char *direction, int verbosity)
const struct got_error *error = NULL;
int pid, pfd[2];
char cmd[64];
+ char escaped_path[PATH_MAX];
const char *argv[11];
int i = 0, j;
*newpid = -1;
*newfd = -1;
+ error = escape_path(escaped_path, sizeof(escaped_path), path);
+ if (error)
+ return error;
+
argv[i++] = GOT_DIAL_PATH_SSH;
if (port != NULL) {
argv[i++] = "-p";
argv[i++] = "--";
argv[i++] = (char *)host;
argv[i++] = (char *)cmd;
- argv[i++] = (char *)path;
+ argv[i++] = (char *)escaped_path;
argv[i++] = NULL;
assert(i <= nitems(argv));
blob - e3fa88deda08736ab31dd16d7515c573e3b9b808
blob + a628193de0dbc52a980b83ef2f3fd49071ce4605
--- regress/cmdline/clone.sh
+++ regress/cmdline/clone.sh
test_done "$testroot" "$ret"
}
+test_clone_quoting() {
+ local testroot=`test_init clone_basic`
+
+ got log -l0 -p -r "$testroot/repo" > $testroot/log-repo
+
+ (cd "$testroot" && cp -R repo "rock'n roll.git")
+
+ got clone -q "ssh://127.0.0.1/$testroot/rock'n roll.git" \
+ "$testroot/rock-clone"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got clone failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got log -l0 -p -r "$testroot/rock-clone" | \
+ sed 's@master, origin/master@master@g' \
+ >$testroot/log-repo-clone
+
+ cmp -s "$testroot/log-repo" "$testroot/log-repo-clone"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "log -p output of cloned repository differs" >&2
+ diff -u "$testroot/log-repo" "$testroot/log-repo-clone"
+ test_done "$testroot" "$ret"
+ fi
+ test_done "$testroot" "$ret"
+}
+
test_clone_list() {
local testroot=`test_init clone_list`
local testurl=ssh://127.0.0.1$testroot
test_parseargs "$@"
run_test test_clone_basic
+run_test test_clone_quoting
run_test test_clone_list
run_test test_clone_branch
run_test test_clone_all