mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 09:12:24 +00:00
bb78583ad2
The basic strategy is described at the top of the new source file sshshare.c. In very brief: an 'upstream' PuTTY opens a Unix-domain socket or Windows named pipe, and listens for connections from other PuTTYs wanting to run sessions on the same server. The protocol spoken down that socket/pipe is essentially the bare ssh-connection protocol, using a trivial binary packet protocol with no encryption, and the upstream has to do some fiddly transformations that I've been referring to as 'channel-number NAT' to avoid resource clashes between the sessions it's managing. This is quite different from OpenSSH's approach of using the Unix- domain socket as a means of passing file descriptors around; the main reason for that is that fd-passing is Unix-specific but this system has to work on Windows too. However, there are additional advantages, such as making it easy for each downstream PuTTY to run its own independent set of port and X11 forwardings (though the method for making the latter work is quite painful). Sharing is off by default, but configuration is intended to be very easy in the normal case - just tick one box in the SSH config panel and everything else happens automatically. [originally from svn r10083]
197 lines
5.3 KiB
C
197 lines
5.3 KiB
C
/*
|
|
* winsecur.c: implementation of winsecur.h.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "putty.h"
|
|
|
|
#if !defined NO_SECURITY
|
|
|
|
#define WINSECUR_GLOBAL
|
|
#include "winsecur.h"
|
|
|
|
int got_advapi(void)
|
|
{
|
|
static int attempted = FALSE;
|
|
static int successful;
|
|
static HMODULE advapi;
|
|
|
|
if (!attempted) {
|
|
attempted = TRUE;
|
|
advapi = load_system32_dll("advapi32.dll");
|
|
successful = advapi &&
|
|
GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
|
|
GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
|
|
GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
|
|
GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
|
|
GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner) &&
|
|
GET_WINDOWS_FUNCTION(advapi, SetEntriesInAclA);
|
|
}
|
|
return successful;
|
|
}
|
|
|
|
int got_crypt(void)
|
|
{
|
|
static int attempted = FALSE;
|
|
static int successful;
|
|
static HMODULE crypt;
|
|
|
|
if (!attempted) {
|
|
attempted = TRUE;
|
|
crypt = load_system32_dll("crypt32.dll");
|
|
successful = crypt &&
|
|
GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory);
|
|
}
|
|
return successful;
|
|
}
|
|
|
|
PSID get_user_sid(void)
|
|
{
|
|
HANDLE proc = NULL, tok = NULL;
|
|
TOKEN_USER *user = NULL;
|
|
DWORD toklen, sidlen;
|
|
PSID sid = NULL, ret = NULL;
|
|
|
|
if (!got_advapi())
|
|
goto cleanup;
|
|
|
|
if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
|
|
GetCurrentProcessId())) == NULL)
|
|
goto cleanup;
|
|
|
|
if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok))
|
|
goto cleanup;
|
|
|
|
if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
goto cleanup;
|
|
|
|
if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
|
|
goto cleanup;
|
|
|
|
if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
|
|
goto cleanup;
|
|
|
|
sidlen = GetLengthSid(user->User.Sid);
|
|
|
|
sid = (PSID)smalloc(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)
|
|
sfree(sid);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int make_private_security_descriptor(DWORD permissions,
|
|
PSECURITY_DESCRIPTOR *psd,
|
|
PSID *networksid,
|
|
PACL *acl,
|
|
char **error)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
|
|
EXPLICIT_ACCESS ea[3];
|
|
int ret = FALSE;
|
|
|
|
*psd = NULL;
|
|
*networksid = NULL;
|
|
*acl = NULL;
|
|
*error = NULL;
|
|
|
|
if (!got_advapi()) {
|
|
*error = dupprintf("unable to load advapi32.dll");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
|
|
0, 0, 0, 0, 0, 0, 0, networksid)) {
|
|
*error = dupprintf("unable to construct SID for "
|
|
"local same-user access only: %s",
|
|
win_strerror(GetLastError()));
|
|
goto cleanup;
|
|
}
|
|
|
|
memset(ea, 0, sizeof(ea));
|
|
ea[0].grfAccessPermissions = permissions;
|
|
ea[0].grfAccessMode = REVOKE_ACCESS;
|
|
ea[0].grfInheritance = NO_INHERITANCE;
|
|
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
|
ea[0].Trustee.ptstrName = "EVERYONE";
|
|
ea[1].grfAccessPermissions = permissions;
|
|
ea[1].grfAccessMode = GRANT_ACCESS;
|
|
ea[1].grfInheritance = NO_INHERITANCE;
|
|
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
|
ea[1].Trustee.ptstrName = "CURRENT_USER";
|
|
ea[2].grfAccessPermissions = permissions;
|
|
ea[2].grfAccessMode = REVOKE_ACCESS;
|
|
ea[2].grfInheritance = NO_INHERITANCE;
|
|
ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
ea[2].Trustee.ptstrName = (LPTSTR)*networksid;
|
|
|
|
if (p_SetEntriesInAclA(2, ea, NULL, acl) != ERROR_SUCCESS || *acl == NULL) {
|
|
*error = dupprintf("unable to construct ACL: %s",
|
|
win_strerror(GetLastError()));
|
|
goto cleanup;
|
|
}
|
|
|
|
*psd = (PSECURITY_DESCRIPTOR)
|
|
LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
if (!*psd) {
|
|
*error = dupprintf("unable to allocate security descriptor: %s",
|
|
win_strerror(GetLastError()));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor(*psd, SECURITY_DESCRIPTOR_REVISION)) {
|
|
*error = dupprintf("unable to initialise security descriptor: %s",
|
|
win_strerror(GetLastError()));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!SetSecurityDescriptorDacl(*psd, TRUE, *acl, FALSE)) {
|
|
*error = dupprintf("unable to set DACL in security descriptor: %s",
|
|
win_strerror(GetLastError()));
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
if (!ret) {
|
|
if (*psd) {
|
|
LocalFree(*psd);
|
|
*psd = NULL;
|
|
}
|
|
if (*networksid) {
|
|
LocalFree(*networksid);
|
|
*networksid = NULL;
|
|
}
|
|
if (*acl) {
|
|
LocalFree(*acl);
|
|
*acl = NULL;
|
|
}
|
|
} else {
|
|
sfree(*error);
|
|
*error = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !defined NO_SECURITY */
|