summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Hunt <chrahunt@gmail.com>2014-05-06 20:13:07 -0400
committerChristopher Hunt <chrahunt@gmail.com>2014-05-06 20:13:07 -0400
commit1a70ecefad8d8019844ea5167e06646d4be0983f (patch)
tree6b22bf4d80d44d672fcb1a74e872d260c7a2bb53
parentc9c378f5beaeb4734719a4cbab07779e08ebd25a (diff)
downloadnet-ssh-1a70ecefad8d8019844ea5167e06646d4be0983f.tar.gz
Progress on 1.9.3 implementation.
-rw-r--r--lib/net/ssh/authentication/pageant.rb109
1 files changed, 105 insertions, 4 deletions
diff --git a/lib/net/ssh/authentication/pageant.rb b/lib/net/ssh/authentication/pageant.rb
index 7ae0b35..a27aeaf 100644
--- a/lib/net/ssh/authentication/pageant.rb
+++ b/lib/net/ssh/authentication/pageant.rb
@@ -33,10 +33,12 @@ module Net; module SSH; module Authentication
dlload 'user32'
dlload 'kernel32'
dlload 'advapi32'
+ SIZEOF_DWORD = DL.sizeof('L')
else
extend DL::Importer
dlload 'user32','kernel32', 'advapi32'
include DL::Win32Types
+ SIZEOF_DWORD = DL::SIZEOF_LONG
end
typealias("LPCTSTR", "char *") # From winnt.h
@@ -46,6 +48,7 @@ module Net; module SSH; module Authentication
typealias("WPARAM", "unsigned int *") # From windef.h
typealias("LPARAM", "long *") # From windef.h
typealias("PDWORD_PTR", "long *") # From basetsd.h
+ typealias("USHORT", "unsigned short") # From windef.h
# From winbase.h, winnt.h
INVALID_HANDLE_VALUE = -1
@@ -64,7 +67,7 @@ module Net; module SSH; module Authentication
# args: hFile, (ignored), flProtect, dwMaximumSizeHigh,
# dwMaximumSizeLow, lpName
- extern 'HANDLE CreateFileMapping(HANDLE, void *, DWORD, DWORD, ' +
+ extern 'HANDLE CreateFileMappingW(HANDLE, void *, DWORD, DWORD, ' +
'DWORD, LPCTSTR)'
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
@@ -82,6 +85,9 @@ module Net; module SSH; module Authentication
'UINT, UINT, PDWORD_PTR)'
# args: none
+ extern 'DWORD GetLastError()'
+
+ # args: none
extern 'HANDLE GetCurrentProcess()'
# args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle
@@ -99,9 +105,103 @@ module Net; module SSH; module Authentication
# args: (out) lpSecurityDescriptor, lpOwnerSid, bOwnerDefaulted
extern 'BOOL SetSecurityDescriptorOwner(LPVOID, LPVOID, BOOL)'
+ # args: pSecurityDescriptor
+ extern 'BOOL IsValidSecurityDescriptor(LPVOID)'
+
+ # Constants needed for security attribute retrieval.
+ # Specifies the access mask corresponding to the desired access
+ # rights.
+ TOKEN_QUERY = 0x8
+
+ # The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum.
+ TOKEN_USER_INFORMATION_CLASS = 1
+
+ # The initial revision level assigned to the security descriptor.
+ REVISION = 1
+
if RUBY_VERSION < "1.9"
alias_method :FindWindow,:findWindow
module_function :FindWindow
+ else
+ # Structs for security attribute functions.
+ TOKEN_USER = struct ['void * SID', 'DWORD ATTRIBUTES']
+ SECURITY_ATTRIBUTES = struct ['DWORD nLength',
+ 'LPVOID lpSecurityDescriptor',
+ 'BOOL bInheritHandle']
+ SECURITY_DESCRIPTOR = struct ['UCHAR Revision', 'UCHAR Sbz1',
+ 'USHORT Control', 'LPVOID Owner',
+ 'LPVOID Group', 'LPVOID Sacl',
+ 'LPVOID Dacl']
+
+ # Retrieves the security attributes for the current user, which
+ # can be used in constructing the shared file mapping.
+ def self.get_security_attributes_for_user
+ user = get_current_user
+ sid = DL::CPtr.new(user.SID)
+
+ sd_information = DL::CPtr.malloc(SECURITY_DESCRIPTOR.size, DL::RUBY_FREE)
+ raise_error_if_zero(
+ InitializeSecurityDescriptor(sd_information.ref, REVISION))
+
+ raise_error_if_zero(
+ SetSecurityDescriptorOwner(sd_information.ref, user.SID.ref, 0))
+ raise_error_if_zero(
+ IsValidSecurityDescriptor(sd_information.ref))
+ nLength = SECURITY_ATTRIBUTES.size
+ lpSecurityDescriptor = sd_information.ref
+ bInheritHandle = 1
+ sa = [nLength2, lpSecurityDescriptor, bInheritHandle].pack("LLC")
+
+ return sa
+ end
+
+ def self.get_current_user
+ token_handle = open_process_token(Win.GetCurrentProcess,
+ TOKEN_QUERY)
+ return get_token_information(token_handle,
+ TOKEN_USER_INFORMATION_CLASS)
+ end
+
+ def self.open_process_token(process_handle, desired_access)
+ token_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
+
+ raise_error_if_zero(
+ OpenProcessToken(process_handle, desired_access,
+ token_handle.ref))
+ return token_handle
+ end
+
+ def self.get_token_information(token_handle,
+ token_information_class)
+ # Hold the size of the information to be returned
+ return_length = DL::CPtr.malloc(SIZEOF_DWORD, DL::RUBY_FREE)
+
+ # Going to throw an INSUFFICIENT_BUFFER_ERROR, but that is ok
+ # here. This is retrieving the size of the information to be
+ # returned.
+ GetTokenInformation(token_handle.to_i,
+ token_information_class,
+ NULL, 0, return_length.ref)
+
+ token_information = DL::CPtr.malloc(return_length.to_i, DL::RUBY_FREE)
+
+ # This call is going to write the requested information to
+ # the memory location referenced by token_information.
+ raise_error_if_zero(
+ GetTokenInformation(token_handle.to_i,
+ token_information_class,
+ token_information.ref,
+ token_information.size,
+ return_length.ref))
+
+ return TOKEN_USER.new(token_information)
+ end
+
+ def self.raise_error_if_zero(result)
+ if result == 0
+ raise "Windows error: #{Win.GetLastError}"
+ end
+ end
end
end
@@ -223,13 +323,14 @@ module Net; module SSH; module Authentication
id = DL.malloc(DL::SIZEOF_LONG)
mapname = "PageantRequest%08x\000" % Win.GetCurrentThreadId()
-
- filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE,
- Win::NULL,
+ security_attributes = DL::CPtr.to_ptr Win.get_security_attributes_for_user
+ filemap = Win.CreateFileMappingW(Win::INVALID_HANDLE_VALUE,
+ security_attributes,
Win::PAGE_READWRITE, 0,
AGENT_MAX_MSGLEN, mapname)
if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
+ puts "Windows error: #{Win.GetLastError}"
raise Net::SSH::Exception,
"Creation of file mapping failed"
end