diff --git a/.gitignore b/.gitignore index c246a72..4d439a9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /*.exe /*.o /cscope.out +/*.stackdump +*~ diff --git a/Makefile b/Makefile index 2c45f85..62952e9 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,14 @@ DOCS = README.md COPYING COPYING.PuTTY OBJS = $(SRCS:.c=.o) DEPS = $(OBJS:.o=.d) -.PHONY: clean all install uninstall cscope +.PHONY: clean all debug install uninstall cscope +all: CFLAGS += -O2 all: $(PROGRAM) +debug: CFLAGS += -O0 -DDEBUG -g +debug: $(PROGRAM) + clean: rm -f cscope.out $(PROGRAM) $(OBJS) $(DEPS) @@ -34,7 +38,8 @@ $(PROGRAM): $(OBJS) $(CC) $(LDFLAGS) $(LOADLIBES) $^ $(LDLIBS) -o $@ CC = gcc -CFLAGS = -O2 -Werror -Wall -Wextra -MMD +CFLAGS = -Werror -Wall -Wextra -MMD + CSCOPE = $(firstword $(shell which cscope mlcscope 2>/dev/null) false) cscope: cscope.out diff --git a/README.md b/README.md index a1fb050..8ed2da6 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,38 @@ It may be possible to share a Cygwin socket with external tools like both runtimes. Use `cygpath --windows {path}` to help normalize paths for system-wide use. +3. **Alternative**: run ssh-pageant at Windows start and set environment variables. + + In this scenario there is no need for additions to .bashrc or a custom sock + path, though you can still use it. + + Create a batch file with the following content: + + @echo off + REM This BAT is intented to be run from cmd or at windows startup. + REM It starts ssh-pageant and sets the environment variables. By doing so all + REM newly started shells should inherit the environment variables and there is + REM no need to run ssh-pageant in every new shell + SET FN=%TEMP%\ssh-agent-init.bat + ssh-pageant -S cmd %* > %FN% + call %FN% + del %FN% + + Now just add this batchfile to you windows startup folder. + + To explain: + + * To work around the missing eval in CMD a temporary batch file is + populated with the output of `ssh-pageant`. After execution it will be + deleted again. + + The batchfile is a modified version of [Russell Davis solution for charade](http://russelldavis.blogspot.co.uk/2011/02/using-charade-to-proxy-cygwin-ssh-agent.html). + + * `%*` is an alias for "all arguments" so additional arguments can be passed to + `ssh-pageant` (e.g. `-k` or `-a`). + + Tested and confirmed to work with Windows 10, cmd.exe, GitBash and Msys2 bash. + ## Options `ssh-pageant` aims to be compatible with `ssh-agent` options, with a few extras: @@ -88,7 +120,7 @@ system-wide use. -v, --version Display version information. -c Generate C-shell commands on stdout. -s Generate Bourne shell commands on stdout. - -S SHELL Generate shell command for "bourne", "csh", or "fish". + -S SHELL Generate shell command for "bourne", "csh", "fish" or "cmd". -k Kill the current ssh-pageant. -d Enable debug mode. -q Enable quiet mode. @@ -115,11 +147,12 @@ To uninstall, just remove the copied files: ## Version History -* 2014-11-23: 1.4 - MSYS support and more robust socket paths. -* 2013-06-23: 1.3 - Allow reusing existing sockets via `-r`/`--reuse`. -* 2012-11-24: 1.2 - Mirror the exit status of child processes. -* 2011-06-12: 1.1 - Fixed SID issues. -* 2010-09-20: 1.0 - Initial release. +* 2018-02-01: 1.4-merl1 - Added cmd support and how to add to windows startup. +* 2014-11-23: 1.4 - MSYS support and more robust socket paths. +* 2013-06-23: 1.3 - Allow reusing existing sockets via `-r`/`--reuse`. +* 2012-11-24: 1.2 - Mirror the exit status of child processes. +* 2011-06-12: 1.1 - Fixed SID issues. +* 2010-09-20: 1.0 - Initial release. ## Contributions diff --git a/main.c b/main.c index 48217f9..b72c052 100755 --- a/main.c +++ b/main.c @@ -33,7 +33,8 @@ for (fd = 0; fd < FD_SETSIZE; ++fd) \ if (FD_ISSET(fd, set)) -typedef enum {BOURNE, C_SH, FISH} shell_type; + +typedef enum {BOURNE, C_SH, FISH, CMD} shell_type; struct fd_buf { int recv, send; @@ -89,9 +90,27 @@ cleanup_signal(int sig) // Create a temporary path for the socket. static void -create_socket_path(char* sockpath, size_t len) +create_socket_path(const shell_type opt_sh, char* sockpath, size_t len) { - char tempdir[] = "/tmp/ssh-XXXXXX"; + char *tempdir; + + if (opt_sh == CMD) { + tempdir = malloc(strlen(getenv("USERNAME")) + strlen("C:\\Users\\\\AppData\\Local\\Temp") + 12); + if(tempdir == NULL) { + fprintf(stderr, "Memory allocation failed"); + return; + } + + snprintf(tempdir,strlen(getenv("USERNAME")) + strlen("C:\\Users\\\\AppData\\Local\\Temp") + 12, "C:\\Users\\%s\\AppData\\Local\\Temp\\ssh-XXXXXX", getenv("USERNAME")); + } else { + tempdir = malloc(strlen("/tmp/ssh-XXXXXX") + 1); + if(tempdir == NULL) { + fprintf(stderr, "Memory allocation failed"); + return; + } + + snprintf(tempdir, strlen("/tmp/ssh-XXXXXX") + 1, "/tmp/ssh-XXXXXX"); + } if (!mkdtemp(tempdir)) cleanup_warn("mkdtemp"); @@ -294,7 +313,7 @@ do_agent_loop(int sockfd) // Quote and escape a string for shell eval. // Caller must free the result. static char * -shell_escape(const char *s) +shell_escape(const char *s, const shell_type opt_sh) { // The pessimistic growth is *4, when every character is ' mapped to '\''. // (No need to be clever.) Add room for outer quotes and terminator. @@ -304,7 +323,8 @@ shell_escape(const char *s) return NULL; char c, *out = mem; - *out++ = '\''; // open the string + if (opt_sh != CMD) + *out++ = '\''; // open the string for (c = *s++; c; c = *s++) { if (c == '\'') { *out++ = '\''; // close, @@ -315,7 +335,8 @@ shell_escape(const char *s) else *out++ = c; // plain copy } - *out++ = '\''; // close the string + if (opt_sh != CMD) + *out++ = '\''; // close the string *out++ = '\0'; // terminate return mem; } @@ -349,6 +370,13 @@ output_unset_env(const shell_type opt_sh) case FISH: printf("set -e SSH_AUTH_SOCK;\n"); printf("set -e SSH_PAGEANT_PID;\n"); + break; + case CMD: + // REG delete because setx does not do proper clean up: + // https://stackoverflow.com/questions/13222724/command-line-to-remove-an-environment-variable-from-the-os-level-configuration + printf("set SSH_AUTH_SOCK= & setx SSH_AUTH_SOCK \"\" > NUL & REG delete HKCU\\Environment /F /V SSH_AUTH_SOCK > NUL 2>&1\n"); + printf("set SSH_PAGEANT_PID= & setx SSH_PAGEANT_PID \"\" > NUL & REG delete HKCU\\Environment /F /V SSH_PAGEANT_PID > NUL 2>&1\n"); + break; } } @@ -373,6 +401,11 @@ output_set_env(const shell_type opt_sh, const int p_set_pid_env, const char *esc if (p_set_pid_env) printf("set -x SSH_PAGEANT_PID %d;\n", pid); break; + case CMD: + printf("set SSH_AUTH_SOCK=%s & setx SSH_AUTH_SOCK %s > NUL\n", escaped_sockpath, escaped_sockpath); + if (p_set_pid_env) + printf("set SSH_PAGEANT_PID=%d & setx SSH_PAGEANT_PID %d > NUL\n", pid, pid); + break; } } @@ -386,6 +419,8 @@ parse_shell_option(const char *shell_name) } else if (!strcasecmp(shell_name, "sh") || !strcasecmp(shell_name, "bourne")) { return BOURNE; + } else if (!strcasecmp(shell_name, "cmd")) { + return CMD; } else { errx(1, "unrecognized shell \"%s\"", shell_name); } @@ -422,7 +457,7 @@ main(int argc, char *argv[]) printf(" -v, --version Display version information.\n"); printf(" -c Generate C-shell commands on stdout.\n"); printf(" -s Generate Bourne shell commands on stdout.\n"); - printf(" -S SHELL Generate shell command for \"bourne\", \"csh\", or \"fish\".\n"); + printf(" -S SHELL Generate shell command for \"bourne\", \"csh\", \"fish\", or \"cmd\".\n"); printf(" -k Kill the current %s.\n", program_invocation_short_name); printf(" -d Enable debug mode.\n"); printf(" -q Enable quiet mode.\n"); @@ -432,7 +467,7 @@ main(int argc, char *argv[]) return 0; case 'v': - printf("ssh-pageant 1.4\n"); + printf("ssh-pageant 1.4-merl1\n"); printf("Copyright (C) 2009-2014 Josh Stone\n"); printf("License GPLv3+: GNU GPL version 3 or later" " .\n"); @@ -498,8 +533,12 @@ main(int argc, char *argv[]) if (kill(pid, SIGTERM) < 0) err(1, "kill(%d)", pid); output_unset_env(opt_sh); - if (!opt_quiet) - printf("echo ssh-pageant pid %d killed;\n", pid); + if (!opt_quiet) { + if (opt_sh == CMD) + printf("echo ssh-pageant pid %d killed\n", pid); + else + printf("echo ssh-pageant pid %d killed;\n", pid); + } return 0; } @@ -516,7 +555,7 @@ main(int argc, char *argv[]) int p_sock_reused = opt_reuse && reuse_socket_path(sockpath); if (!p_sock_reused) { if (!sockpath[0]) - create_socket_path(sockpath, sizeof(sockpath)); + create_socket_path(opt_sh, sockpath, sizeof(sockpath)); sockfd = open_auth_socket(sockpath); } @@ -543,13 +582,17 @@ main(int argc, char *argv[]) if (pid < 0) cleanup_warn("fork"); if (pid > 0) { - char *escaped_sockpath = shell_escape(sockpath); + char *escaped_sockpath = shell_escape(sockpath, opt_sh); if (!escaped_sockpath) cleanup_warn("shell_escape"); output_set_env(opt_sh, p_set_pid_env, escaped_sockpath, pid); free(escaped_sockpath); - if (p_set_pid_env && !opt_quiet) - printf("echo ssh-pageant pid %d;\n", pid); + if (p_set_pid_env && !opt_quiet) { + if (opt_sh == CMD) + printf("echo ssh-pageant pid %d\n", pid); + else + printf("echo ssh-pageant pid %d;\n", pid); + } if (p_daemonize) return 0; }