Permalink
Browse files

First commit for ssh-pageant

Introducing ssh-agent, an ssh authentication agent that just passes the
buck to Pageant (from the PuTTY suite).  This lets you use a single key
store for both PuTTY and Cygwin's ssh commands.

It's fairly crude, but there's enough here to be useful.  Connections
are completely serialized, and it's assumed that the clients are well-
behaved.  99% of the time that's probably fine.
  • Loading branch information...
cuviper committed Apr 20, 2009
0 parents commit bde5320ce786636309e7f85d66348a7a892f5235
Showing with 952 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +674 −0 COPYING
  3. +2 −0 INSTALL
  4. +15 −0 Makefile
  5. +153 −0 main.c
  6. +90 −0 winpgntc.c
  7. +16 −0 winpgntc.h
@@ -0,0 +1,2 @@
+/*.exe
+/*.o
674 COPYING

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,2 @@
+To compile ssh-pageant, just run 'make'.
+To install, copy ssh-pageant.exe to an appropriate place.
@@ -0,0 +1,15 @@
+ssh-pageant.exe: main.o winpgntc.o
+ $(CC) $(LDFLAGS) $(LOADLIBES) $^ $(LDLIBS) -o $@
+
+main.o: main.c winpgntc.h
+winpgntc.o: winpgntc.c winpgntc.h
+
+.PHONY: clean all
+
+clean:
+ rm -f ssh-pageant.exe main.o winpgntc.o
+
+all: ssh-pageant.exe
+
+CFLAGS = -O2 -Werror -Wall -Wextra
+LDFLAGS = -Wl,--strip-all
153 main.c
@@ -0,0 +1,153 @@
+/*
+ * ssh-pageant main code.
+ * Copyright (C) 2009 Josh Stone
+ *
+ * This file is part of ssh-pageant, and is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "winpgntc.h"
+
+
+#define SSH_AGENT_FAILURE 5
+
+
+static char tempdir[UNIX_PATH_LEN] = "";
+static char sockpath[UNIX_PATH_LEN] = "";
+
+
+__attribute__((noreturn)) static void
+cleanup_exit(int ret)
+{
+ unlink(sockpath);
+ rmdir(tempdir);
+ exit(ret);
+}
+
+
+static void
+cleanup_signal(int sig __attribute__((unused)))
+{
+ cleanup_exit(0);
+}
+
+
+static int
+open_auth_socket()
+{
+ struct sockaddr_un addr;
+ mode_t um;
+ int fd;
+
+ strlcpy(tempdir, "/tmp/ssh-XXXXXX", sizeof(tempdir));
+ if (!mkdtemp(tempdir)) {
+ perror("mkdtemp");
+ cleanup_exit(1);
+ }
+
+ snprintf(sockpath, sizeof(sockpath), "%s/agent.%d", tempdir, getpid());
+ sockpath[sizeof(sockpath) - 1] = '\0';
+
+ fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("socket");
+ cleanup_exit(1);
+ }
+
+ addr.sun_family = AF_UNIX;
+ strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+ um = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("bind");
+ umask(um);
+ cleanup_exit(1);
+ }
+ umask(um);
+
+ if (listen(fd, 128) < 0) {
+ perror("listen");
+ cleanup_exit(1);
+ }
+
+ return fd;
+}
+
+
+static void
+handle_connection(int s)
+{
+ static char reply_error[5] = { 0, 0, 0, 1, SSH_AGENT_FAILURE };
+ uint32_t nlen;
+ while (recv(s, &nlen, 4, MSG_PEEK | MSG_WAITALL) == 4) {
+ int len = 4 + ntohl(nlen);
+ void *buf = malloc(len);
+ if (buf && recv(s, buf, len, MSG_WAITALL) == len) {
+ void *reply;
+ int replylen;
+ agent_query(buf, len, &reply, &replylen);
+ if (reply) {
+ send(s, reply, replylen, 0);
+ free(reply);
+ } else
+ send(s, &reply_error, sizeof(reply_error), 0);
+ }
+ free(buf);
+ }
+ close(s);
+}
+
+
+static void
+daemonize()
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ cleanup_exit(1);
+ exit(1);
+ }
+ if (pid > 0) {
+ printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", sockpath);
+ printf("SSH_PAGEANT_PID=%d; export SSH_PAGEANT_PID;\n", pid);
+ //printf("echo ssh-pageant pid %d\n", pid);
+ exit(0);
+ }
+
+ if (setsid() < 0) {
+ perror("setsid");
+ cleanup_exit(1);
+ }
+
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+}
+
+
+int
+main()
+{
+ int sockfd, s;
+
+ signal(SIGINT, cleanup_signal);
+ signal(SIGHUP, cleanup_signal);
+ signal(SIGTERM, cleanup_signal);
+
+ sockfd = open_auth_socket();
+ daemonize();
+ while ((s = accept(sockfd, NULL, 0)) >= 0)
+ handle_connection(s);
+ cleanup_exit(1);
+}
@@ -0,0 +1,90 @@
+/*
+ * Pageant client code.
+ * Copyright (C) 2009 Josh Stone
+ *
+ * This file is part of ssh-pageant, and is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This file is derived from part of the PuTTY program, whose original
+ * license is reproduced below.
+ *
+ *
+ * PuTTY is copyright 1997-2007 Simon Tatham.
+ *
+ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
+ * Kuhn, and CORE SDI S.A.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+
+#include "winpgntc.h"
+
+#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
+#define AGENT_MAX_MSGLEN 8192
+
+int agent_query(void *in, int inlen, void **out, int *outlen)
+{
+ HWND hwnd;
+ char mapname[] = "PageantRequest12345678";
+ HANDLE filemap;
+ unsigned char *p, *ret;
+ int id, retlen;
+ COPYDATASTRUCT cds;
+
+ *out = NULL;
+ *outlen = 0;
+
+ hwnd = FindWindow("Pageant", "Pageant");
+ if (!hwnd)
+ return 1; /* *out == NULL, so failure */
+ sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
+ filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
+ 0, AGENT_MAX_MSGLEN, mapname);
+ if (filemap == NULL || filemap == INVALID_HANDLE_VALUE)
+ return 1; /* *out == NULL, so failure */
+ p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
+ memcpy(p, in, inlen);
+ cds.dwData = AGENT_COPYDATA_ID;
+ cds.cbData = 1 + strlen(mapname);
+ cds.lpData = mapname;
+
+ id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
+ if (id > 0) {
+ retlen = 4 + ntohl(*(uint32_t *)p);
+ ret = (unsigned char *)malloc(retlen);
+ if (ret) {
+ memcpy(ret, p, retlen);
+ *out = ret;
+ *outlen = retlen;
+ }
+ }
+ UnmapViewOfFile(p);
+ CloseHandle(filemap);
+ return 1;
+}
@@ -0,0 +1,16 @@
+/*
+ * Pageant client header.
+ * Copyright (C) 2009 Josh Stone
+ *
+ * This file is part of ssh-pageant, and is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ */
+
+#ifndef __WINPGNTC_H__
+#define __WINPGNTC_H__
+
+extern int agent_query(void *in, int inlen, void **out, int *outlen);
+
+#endif /* __WINPGNTC_H__ */

0 comments on commit bde5320

Please sign in to comment.