Skip to content

Commit

Permalink
First commit for ssh-pageant
Browse files Browse the repository at this point in the history
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 bde5320
Show file tree
Hide file tree
Showing 7 changed files with 952 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
/*.exe
/*.o
674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions INSTALL
@@ -0,0 +1,2 @@
To compile ssh-pageant, just run 'make'.
To install, copy ssh-pageant.exe to an appropriate place.
15 changes: 15 additions & 0 deletions Makefile
@@ -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 changes: 153 additions & 0 deletions 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);
}
90 changes: 90 additions & 0 deletions winpgntc.c
@@ -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;
}
16 changes: 16 additions & 0 deletions winpgntc.h
@@ -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.