diff options
author | Christopher Hunt <chrahunt@gmail.com> | 2014-05-06 20:13:07 -0400 |
---|---|---|
committer | Christopher Hunt <chrahunt@gmail.com> | 2014-05-06 20:13:07 -0400 |
commit | 1a70ecefad8d8019844ea5167e06646d4be0983f (patch) | |
tree | 6b22bf4d80d44d672fcb1a74e872d260c7a2bb53 | |
parent | c9c378f5beaeb4734719a4cbab07779e08ebd25a (diff) | |
download | net-ssh-1a70ecefad8d8019844ea5167e06646d4be0983f.tar.gz |
Progress on 1.9.3 implementation.
-rw-r--r-- | lib/net/ssh/authentication/pageant.rb | 109 |
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 |