Created
May 11, 2020 23:09
-
-
Save AudriusButkevicius/59d94abaec217714569fb74a1f3857cc to your computer and use it in GitHub Desktop.
This file contains hidden or 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
package dummy | |
import ( | |
"errors" | |
"runtime" | |
"syscall" | |
"unsafe" | |
) | |
type CredentialsPromptFlag uint32 | |
const ( | |
// Specifies that a user interface will be shown even if the credentials can be returned from an existing credential | |
// in credential manager. This flag is permitted only if GenericCredentials is also specified. | |
AlwaysShowUI CredentialsPromptFlag = 0x00080 | |
// Populate the combo box with the prompt for a user name. | |
CompleteUsername CredentialsPromptFlag = 0x00800 | |
// Do not store credentials or display check boxes. You can pass CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX with this flag to | |
// display the Save check box only, and the result is returned in the pfSave output parameter. | |
DoNotPersist CredentialsPromptFlag = 0x00002 | |
// Populate the combo box with user name/password only. Do not display certificates or smart cards in the combo box. | |
ExcludeCertificates CredentialsPromptFlag = 0x00008 | |
// Specifies that the caller will call CredUIConfirmCredentials after checking to determine whether the returned | |
// credentials are actually valid. This mechanism ensures that credentials that are not valid are not saved to the | |
// credential manager. Specify this flag in all cases unless CREDUI_FLAGS_DO_NOT_PERSIST is specified. | |
ExpectConfirmation CredentialsPromptFlag = 0x20000 | |
// Consider the credentials entered by the user to be generic credentials. | |
GenericCredentials CredentialsPromptFlag = 0x40000 | |
// Notify the user of insufficient credentials by displaying the "Logon unsuccessful" balloon tip. | |
IncorrectPassword CredentialsPromptFlag = 0x00001 | |
// Do not allow the user to change the supplied user name. | |
KeepUsername CredentialsPromptFlag = 0x100000 | |
// Populate the combo box with the password only. Do not allow a user name to be entered. | |
PasswordOnlyOk CredentialsPromptFlag = 0x00200 | |
// Do not show the Save check box, but the credential is saved as though the box were shown and selected. | |
Persist CredentialsPromptFlag = 0x01000 | |
// Populate the combo box with local administrators only.Windows XP Home Edition: This flag will filter out the | |
// well-known Administrator account. | |
RequestAdministrator CredentialsPromptFlag = 0x00004 | |
// Populate the combo box with certificates and smart cards only. Do not allow a user name to be entered. | |
RequireCertificate CredentialsPromptFlag = 0x00010 | |
// Populate the combo box with certificates or smart cards only. Do not allow a user name to be entered. | |
RequireSmartcard CredentialsPromptFlag = 0x00100 | |
// This flag is meaningful only in locating a matching credential to prefill the dialog box, should authentication | |
// fail. When this flag is specified, wildcard credentials will not be matched. It has no effect when writing a | |
// credential. CredUI does not create credentials that contain wildcard characters. Any found were either created | |
// explicitly by the user or created programmatically, as happens when a RAS connection is made. | |
ServerCredential CredentialsPromptFlag = 0x04000 | |
// If the check box is selected, show the Save check box and return TRUE in the pfSave output parameter, otherwise, | |
// return FALSE. Check box uses the value in pfSave by default. | |
ShowSaveCheckBox CredentialsPromptFlag = 0x00040 | |
// The credential is a "runas" credential. The TargetName parameter specifies the name of the command or program | |
// being run. It is used for prompting purposes only. | |
UsernameTargetCredentials CredentialsPromptFlag = 0x80000 | |
// Check that the user name is valid. | |
ValidateUsername CredentialsPromptFlag = 0x00400 | |
sys_ERROR_CANCELLED = 1223 | |
sys_ERROR_INVALID_FLAGS = 1004 | |
sys_ERROR_INVALID_PARAMETER = 87 | |
sys_NO_ERROR = 0 | |
sys_ERROR_NO_SUCH_LOGON_SESSION = 1312 | |
sys_CREDUI_MAX_MESSAGE_LENGTH = 32767 | |
sys_CREDUI_MAX_CAPTION_LENGTH = 128 | |
sys_CREDUI_MAX_GENERIC_TARGET_LENGTH = 32767 | |
sys_CREDUI_MAX_DOMAIN_TARGET_LENGTH = 337 | |
sys_CREDUI_MAX_USERNAME_LENGTH = 513 | |
sys_CREDUI_MAX_PASSWORD_LENGTH = 256 | |
) | |
var ( | |
procCredUIPromptForCredentials proc = credui.NewProc("CredUIPromptForCredentialsW") | |
credui = syscall.NewLazyDLL("credui.dll") | |
ErrCancelled = errors.New("cancelled") | |
ErrInvalidFlags = errors.New("invalid flags") | |
ErrInvalidParameter = errors.New("invalid parameter") | |
ErrNoSuchLogonSession = errors.New("no such logon session") | |
) | |
type sys_CREDUI_INFO struct { | |
Size uint32 | |
ParentWindow syscall.Handle | |
MessageText *uint16 | |
CaptionText *uint16 | |
Banner syscall.Handle | |
} | |
type PromptSettings struct { | |
Target string | |
Errno syscall.Errno | |
Flags CredentialsPromptFlag | |
Username string | |
Password string | |
Save bool | |
Message string | |
Caption string | |
ParentWindow syscall.Handle | |
BannerImage syscall.Handle | |
} | |
type PromptResponse struct { | |
Username string | |
Password string | |
Save bool | |
} | |
func createUiInfo(settings PromptSettings) (*sys_CREDUI_INFO, error) { | |
uiInfo := new(sys_CREDUI_INFO) | |
uiInfo.ParentWindow = settings.ParentWindow | |
var err error | |
if len(settings.Message) > 0 { | |
if uiInfo.MessageText, err = syscall.UTF16PtrFromString(settings.Message); err != nil { | |
return nil, err | |
} | |
} | |
if len(settings.Caption) > 0 { | |
if uiInfo.CaptionText, err = syscall.UTF16PtrFromString(settings.Caption); err != nil { | |
return nil, err | |
} | |
} | |
uiInfo.Banner = settings.BannerImage | |
uiInfo.Size = uint32(unsafe.Sizeof(*uiInfo)) | |
return uiInfo, nil | |
} | |
func validateSettings(settings PromptSettings) error { | |
targetMaxLength := sys_CREDUI_MAX_DOMAIN_TARGET_LENGTH | |
if settings.Flags&GenericCredentials == GenericCredentials { | |
targetMaxLength = sys_CREDUI_MAX_GENERIC_TARGET_LENGTH | |
} | |
if len(settings.Target) > targetMaxLength { | |
return errors.New("target too long") | |
} | |
if len(settings.Username) > sys_CREDUI_MAX_USERNAME_LENGTH { | |
return errors.New("username too long") | |
} | |
if len(settings.Password) > sys_CREDUI_MAX_PASSWORD_LENGTH { | |
return errors.New("password too long") | |
} | |
if len(settings.Message) > sys_CREDUI_MAX_MESSAGE_LENGTH { | |
return errors.New("message too long") | |
} | |
if len(settings.Caption) > sys_CREDUI_MAX_CAPTION_LENGTH { | |
return errors.New("caption too long") | |
} | |
return nil | |
} | |
func Prompt(settings PromptSettings) (PromptResponse, error) { | |
if err := validateSettings(settings); err != nil { | |
return PromptResponse{}, err | |
} | |
targetPtr, err := syscall.UTF16PtrFromString(settings.Target) | |
if err != nil { | |
return PromptResponse{}, err | |
} | |
uiInfo, err := createUiInfo(settings) | |
if err != nil { | |
return PromptResponse{}, err | |
} | |
usernameBuf := make([]uint16, sys_CREDUI_MAX_USERNAME_LENGTH, sys_CREDUI_MAX_USERNAME_LENGTH) | |
if usernameUtf16, err := syscall.UTF16FromString(settings.Username); err != nil { | |
return PromptResponse{}, err | |
} else { | |
copy(usernameBuf, usernameUtf16) | |
} | |
passwordBuf := make([]uint16, sys_CREDUI_MAX_PASSWORD_LENGTH, sys_CREDUI_MAX_PASSWORD_LENGTH) | |
if passwordUtf16, err := syscall.UTF16FromString(settings.Password); err != nil { | |
return PromptResponse{}, err | |
} else { | |
copy(passwordBuf, passwordUtf16) | |
} | |
save := settings.Save | |
response := PromptResponse{} | |
ret, _, _ := procCredUIPromptForCredentials.Call( | |
uintptr(unsafe.Pointer(uiInfo)), | |
uintptr(unsafe.Pointer(targetPtr)), | |
0, | |
uintptr(settings.Errno), | |
uintptr(unsafe.Pointer(&usernameBuf[0])), | |
uintptr(cap(usernameBuf)), | |
uintptr(unsafe.Pointer(&passwordBuf[0])), | |
uintptr(cap(passwordBuf)), | |
uintptr(unsafe.Pointer(&save)), | |
uintptr(settings.Flags), | |
) | |
response.Username = syscall.UTF16ToString(usernameBuf) | |
response.Password = syscall.UTF16ToString(passwordBuf) | |
response.Save = save | |
switch ret { | |
case sys_ERROR_CANCELLED: | |
err = ErrCancelled | |
case sys_ERROR_INVALID_FLAGS: | |
err = ErrInvalidFlags | |
case sys_ERROR_INVALID_PARAMETER: | |
err = ErrInvalidParameter | |
case sys_ERROR_NO_SUCH_LOGON_SESSION: | |
err = ErrNoSuchLogonSession | |
case sys_NO_ERROR: | |
err = nil | |
} | |
return response, err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment