Module: Lich::Common::GUI::WindowsCredentialManager
- Extended by:
- FFI::Library
- Defined in:
- documented/common/gui/windows_credential_manager.rb
Overview
Provides an interface to the Windows Credential Manager. This module allows storing, retrieving, and deleting credentials on Windows.
Defined Under Namespace
Classes: CredentialStruct
Constant Summary collapse
- CRED_TYPE_GENERIC =
CRED_TYPE values Represents a generic credential type.
1- CRED_TYPE_DOMAIN_PASSWORD =
2- CRED_TYPE_DOMAIN_CERTIFICATE =
3- CRED_TYPE_DOMAIN_VISIBLE_PASSWORD =
4- CRED_TYPE_GENERIC_CERTIFICATE =
5- CRED_TYPE_DOMAIN_EXTENDED =
6- CRED_PERSIST_SESSION =
CRED_PERSIST values Represents a credential that is valid for the current session.
1- CRED_PERSIST_LOCAL_MACHINE =
2- CRED_PERSIST_ENTERPRISE =
3- CRED_MAX_CREDENTIAL_BLOB_SIZE =
Max credential size (512KB) Maximum size for a credential blob, set to 512KB.
512 * 1024
Class Method Summary collapse
-
.available? ⇒ Boolean
Checks if the Windows Credential Manager is available.
-
.delete_credential(target_name) ⇒ Boolean
Deletes a credential from the Windows Credential Manager.
-
.retrieve_credential(target_name) ⇒ String?
Retrieves a credential from the Windows Credential Manager.
-
.store_credential(target_name, username, password, comment = nil, persist = CRED_PERSIST_LOCAL_MACHINE) ⇒ Boolean
Stores a credential in the Windows Credential Manager.
Class Method Details
.available? ⇒ Boolean
Checks if the Windows Credential Manager is available.
75 76 77 78 79 80 81 82 83 84 85 |
# File 'documented/common/gui/windows_credential_manager.rb', line 75 def available? return false unless OS.windows? # Simple test: try to allocate credential structure begin FFI::MemoryPointer.new(CredentialStruct) true rescue false end end |
.delete_credential(target_name) ⇒ Boolean
Deletes a credential from the Windows Credential Manager.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'documented/common/gui/windows_credential_manager.rb', line 196 def delete_credential(target_name) return false unless available? begin target_name_wide = string_to_wide(target_name) # Call CredDeleteW result = CredDeleteW(target_name_wide, CRED_TYPE_GENERIC, 0) if result true else error_code = GetLastError Lich.log "error: CredDeleteW failed with error code #{error_code}" false end rescue StandardError => e Lich.log "error: Failed to delete credential: #{e.}" false end end |
.retrieve_credential(target_name) ⇒ String?
Retrieves a credential from the Windows Credential Manager.
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'documented/common/gui/windows_credential_manager.rb', line 152 def retrieve_credential(target_name) return nil unless available? begin target_name_wide = string_to_wide(target_name) cred_ptr = FFI::MemoryPointer.new(:pointer) # Call CredReadW result = CredReadW(target_name_wide, CRED_TYPE_GENERIC, 0, cred_ptr) if result cred = cred_ptr.read_pointer credential = CredentialStruct.new(cred) # Extract password blob blob_ptr = credential[:credential_blob] blob_size = credential[:credential_blob_size] password_blob = blob_ptr.read_bytes(blob_size) # Password blob is stored as UTF-8 bytes; convert safely with encoding handling password = password_blob.b.force_encoding('UTF-8') # Free credential structure CredFree(cred) password else error_code = GetLastError # ERROR_NOT_FOUND = 1168, so only log unexpected errors Lich.log "error: CredReadW failed with error code #{error_code}" unless error_code == 1168 nil end rescue StandardError # Don't log as error for "not found" - it's expected on first run # Only actual failures (encoding, access, API errors) should log nil end end |
.store_credential(target_name, username, password, comment = nil, persist = CRED_PERSIST_LOCAL_MACHINE) ⇒ Boolean
Stores a credential in the Windows Credential Manager.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'documented/common/gui/windows_credential_manager.rb', line 97 def store_credential(target_name, username, password, comment = nil, persist = CRED_PERSIST_LOCAL_MACHINE) return false unless available? begin credential = CredentialStruct.new # Convert strings to wide characters (UTF-16LE) target_name_wide = string_to_wide(target_name) username_wide = string_to_wide(username) # Store password as UTF-8 bytes (as binary data, not text) password_bytes = password.to_s.encode('UTF-8') password_blob = password_bytes.b comment_wide = comment ? string_to_wide(comment) : FFI::Pointer.new(:pointer, 0) Lich.log "debug: Storing credential - target: #{target_name}, user: #{username}, pass_size: #{password_blob.bytesize}, persist: #{persist}" # Allocate memory for credential blob (password data) blob_ptr = FFI::MemoryPointer.new(:uint8, password_blob.bytesize) blob_ptr.put_bytes(0, password_blob) # Fill credential structure credential[:flags] = 0 credential[:type] = CRED_TYPE_GENERIC credential[:target_name] = target_name_wide credential[:comment] = comment_wide credential[:credential_blob_size] = password_blob.size credential[:credential_blob] = blob_ptr credential[:persist] = persist credential[:attribute_count] = 0 credential[:attributes] = FFI::Pointer.new(:pointer, 0) credential[:user_name] = username_wide # Call CredWriteW - pass pointer to the credential struct result = CredWriteW(credential, 0) if result Lich.log "debug: Credential stored successfully" true else error_code = GetLastError Lich.log "error: CredWriteW failed with error code #{error_code}" false end rescue StandardError => e Lich.log "error: Failed to store credential: #{e.class.name}: #{e.}" false end end |