Skip to content

Commit

Permalink
Initial commit: tnaegap-hss, a way to use Pageant applications with o…
Browse files Browse the repository at this point in the history
…penssh
  • Loading branch information
TvdW committed Apr 22, 2018
0 parents commit 2b320ca
Show file tree
Hide file tree
Showing 5 changed files with 386 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.exe
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CC = cc
CFLAGS = -Wall

all:
$(CC) $(CFLAGS) -o tnaegap-hss.exe security.c tnaegap-hss.c
140 changes: 140 additions & 0 deletions security.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <aclapi.h>

#include "security.h"

/*
* Versions of Pageant prior to 0.61 expected this SID on incoming
* communications. For backwards compatibility, and more particularly
* for compatibility with derived works of PuTTY still using the old
* Pageant client code, we accept it as an alternative to the one
* returned from get_user_sid() in winpgntc.c.
*/
PSID get_default_sid(void)
{
HANDLE proc = NULL;
DWORD sidlen;
PSECURITY_DESCRIPTOR psd = NULL;
PSID sid = NULL, copy = NULL, ret = NULL;

if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
GetCurrentProcessId())) == NULL)
goto cleanup;

if (GetSecurityInfo(proc, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
&sid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)
goto cleanup;

sidlen = GetLengthSid(sid);

copy = (PSID)malloc(sidlen);

if (!CopySid(sidlen, copy, sid))
goto cleanup;

/* Success. Move sid into the return value slot, and null it out
* to stop the cleanup code freeing it. */
ret = copy;
copy = NULL;

cleanup:
if (proc != NULL)
CloseHandle(proc);
if (psd != NULL)
LocalFree(psd);
if (copy != NULL)
free(copy);

return ret;
}

PSID get_user_sid(void)
{
HANDLE proc = NULL, tok = NULL;
TOKEN_USER *user = NULL;
DWORD toklen, sidlen;
PSID sid = NULL, ret = NULL;

if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
GetCurrentProcessId())) == NULL)
goto cleanup;

if (!OpenProcessToken(proc, TOKEN_QUERY, &tok))
goto cleanup;

if (!GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto cleanup;

if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
goto cleanup;

if (!GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
goto cleanup;

sidlen = GetLengthSid(user->User.Sid);

sid = (PSID)malloc(sidlen);

if (!CopySid(sidlen, sid, user->User.Sid))
goto cleanup;

/* Success. Move sid into the return value slot, and null it out
* to stop the cleanup code freeing it. */
ret = sid;
sid = NULL;

cleanup:
if (proc != NULL)
CloseHandle(proc);
if (tok != NULL)
CloseHandle(tok);
if (user != NULL)
LocalFree(user);
if (sid != NULL)
free(sid);

return ret;
}

int check_security(HANDLE obj)
{
PSID objowner = NULL, defaultsid = NULL, usersid = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
int ret = 0;

if (GetSecurityInfo(obj, SE_KERNEL_OBJECT,
OWNER_SECURITY_INFORMATION,
&objowner, NULL, NULL, NULL,
&psd) != ERROR_SUCCESS) {
goto fail;
}

if (!objowner) {
goto fail;
}

defaultsid = get_default_sid();
if (defaultsid && EqualSid(defaultsid, objowner)) {
ret = 1;
goto done;
}

usersid = get_user_sid();
if (usersid && EqualSid(usersid, objowner)) {
ret = 1;
goto done;
}

fail:
ret = 0;

done:
if (defaultsid)
free(defaultsid);
if (usersid)
free(usersid);
if (psd)
LocalFree(psd);

return ret;
}
3 changes: 3 additions & 0 deletions security.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <windows.h>

int check_security(HANDLE obj);
237 changes: 237 additions & 0 deletions tnaegap-hss.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

#include "security.h"

#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */

int answer_msg(void *msg)
{
size_t msg_size, msg_pos;
unsigned int query_size;
MEMORY_BASIC_INFORMATION info;
int fd = -1, msg_done;
struct sockaddr_un addr;
char *error = NULL;

VirtualQuery(msg, &info, sizeof(info));
msg_size = info.RegionSize;

if (msg_size < 4) {
error = "Message less than 4 bytes?";
goto done;
}

query_size = ntohl(*(unsigned int*)msg);
if (query_size + 4 > msg_size) {
error = "Unlikely query size";
goto done;
}

if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
error = "Can't create unix socket";
goto done;
}

memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, getenv("SSH_AUTH_SOCK"), sizeof(addr.sun_path)-1);

if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
error = "Can't connect to unix socket";
goto done;
}

if (write(fd, msg, query_size+4) != query_size+4) {
error = "Partial write...";
goto done;
}

msg_pos = 0;
msg_done = 0;
while (msg_pos < msg_size && !msg_done) {
int rc;
unsigned int response_size;

rc = read(fd, msg+msg_pos, msg_size-msg_pos);
if (rc <= 0) {
error = "Failed to read from socket";
goto done;
}

msg_pos += rc;
if (msg_pos >= 4) {
response_size = ntohl(*(unsigned int*)msg) + 4;
if (response_size >= msg_pos) {
msg_done = 1;
} else if (response_size > msg_size) {
error = "Impossibly long answer";
goto done;
}
}
}

done:
if (fd > 0)
close(fd);
if (error)
fprintf(stderr, "[warn] %s\n", error);
return error ? 0 : 1;
}

LRESULT CALLBACK
WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
return 0;
break;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;

case WM_COPYDATA:
{
COPYDATASTRUCT *cds;
char *mapname;
HANDLE filemap;
void *p;
int ret = 0;

cds = (COPYDATASTRUCT*)lParam;
if (cds->dwData != AGENT_COPYDATA_ID)
return 0; /* Message wasn't for us */

mapname = (char*)cds->lpData;
if (mapname[cds->cbData - 1] != '\0')
return 0; /* Invalid string */

filemap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname);
if (filemap != NULL && filemap != INVALID_HANDLE_VALUE) {
if (check_security(filemap)) {
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
ret = answer_msg(p);
UnmapViewOfFile(p);
}
}
CloseHandle(filemap);

return ret;
break;
}
}

return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int CALLBACK
myMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
WNDCLASSEX wndclass;
BOOL bRet;
MSG msg;

memset(&wndclass, 0, sizeof(wndclass));
wndclass.lpszClassName = "Pageant";
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
RegisterClassEx(&wndclass);

hwnd = CreateWindow(
"Pageant",
"Pageant",
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);

while ((bRet = GetMessage(&msg, hwnd, 0, 0)) != 0) {
if (bRet == -1) {
return 1;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

void* start_thread(void* arg)
{
int *out = (int*)arg;
*out = myMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW);
return NULL;
}

int main(int argc, char** argv)
{
int new_only = 0;

int i;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
int j;
for (j = 1; argv[i][j] != '\0'; j++) {
switch (argv[i][j]) {
case 'n':
new_only = 1;
break;
case 'h':
printf("Usage: %s [flags]\n\n", argv[0]);
printf("Valid flags:\n");
printf(" -n Exit quietly if there's already a Pageant process\n");
printf(" -h Shows this help section\n");
return 0;
break;
default:
fprintf(stderr, "Invalid flag %c\n", argv[i][j]);
return 1;
}
}
}
}

if (FindWindow("Pageant", "Pageant") != NULL) {
if (new_only) {
return 0;
}
fprintf(stderr, "Pageant already running, not starting a new one\n");
return 1;
}

if (!getenv("SSH_AUTH_SOCK")) {
fprintf(stderr, "No value for required environment variable SSH_AUTH_SOCK\n");
return 1;
}

pthread_t thread;
int out;
if (pthread_create(&thread, NULL, start_thread, &out)) {
fprintf(stderr, "Can't spawn thread\n");
return 1;
}
if (pthread_join(thread, NULL)) {
fprintf(stderr, "Failed to wait for thread\n");
return 1;
}
return out;
}

0 comments on commit 2b320ca

Please sign in to comment.