Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
/*.exe
/*.o
/cscope.out
/*.stackdump
*~
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
Expand Down
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand All @@ -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
Expand Down
71 changes: 57 additions & 14 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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;
}
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -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");
Expand All @@ -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"
" <http://gnu.org/licenses/gpl.html>.\n");
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}

Expand All @@ -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;
}
Expand Down