-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit: tnaegap-hss, a way to use Pageant applications with o…
…penssh
- Loading branch information
0 parents
commit 2b320ca
Showing
5 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#include <windows.h> | ||
|
||
int check_security(HANDLE obj); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |