Merge pull request #9 from 3v1n0/binary-protocol
transaction: Add support for Binary conversation
This commit is contained in:
@@ -1,11 +1,21 @@
|
|||||||
// Package pam provides a wrapper for the PAM application API.
|
// Package pam provides a wrapper for the PAM application API.
|
||||||
package pam
|
package pam
|
||||||
|
|
||||||
|
//#cgo CFLAGS: -Wall -std=c99
|
||||||
|
//#cgo LDFLAGS: -lpam
|
||||||
|
//
|
||||||
//#include <security/pam_appl.h>
|
//#include <security/pam_appl.h>
|
||||||
//#include <stdlib.h>
|
//#include <stdlib.h>
|
||||||
//#include <stdint.h>
|
//#include <stdint.h>
|
||||||
//#cgo CFLAGS: -Wall -std=c99
|
//
|
||||||
//#cgo LDFLAGS: -lpam
|
//#ifdef PAM_BINARY_PROMPT
|
||||||
|
//#define BINARY_PROMPT_IS_SUPPORTED 1
|
||||||
|
//#else
|
||||||
|
//#include <limits.h>
|
||||||
|
//#define PAM_BINARY_PROMPT INT_MAX
|
||||||
|
//#define BINARY_PROMPT_IS_SUPPORTED 0
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
//void init_pam_conv(struct pam_conv *conv, uintptr_t);
|
//void init_pam_conv(struct pam_conv *conv, uintptr_t);
|
||||||
//int pam_start_confdir(const char *service_name, const char *user, const struct pam_conv *pam_conversation, const char *confdir, pam_handle_t **pamh) __attribute__ ((weak));
|
//int pam_start_confdir(const char *service_name, const char *user, const struct pam_conv *pam_conversation, const char *confdir, pam_handle_t **pamh) __attribute__ ((weak));
|
||||||
//int check_pam_start_confdir(void);
|
//int check_pam_start_confdir(void);
|
||||||
@@ -36,6 +46,9 @@ const (
|
|||||||
// TextInfo indicates the conversation handler should display some
|
// TextInfo indicates the conversation handler should display some
|
||||||
// text.
|
// text.
|
||||||
TextInfo = C.PAM_TEXT_INFO
|
TextInfo = C.PAM_TEXT_INFO
|
||||||
|
// BinaryPrompt indicates the conversation handler that should implement
|
||||||
|
// the private binary protocol
|
||||||
|
BinaryPrompt = C.PAM_BINARY_PROMPT
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConversationHandler is an interface for objects that can be used as
|
// ConversationHandler is an interface for objects that can be used as
|
||||||
@@ -47,6 +60,23 @@ type ConversationHandler interface {
|
|||||||
RespondPAM(Style, string) (string, error)
|
RespondPAM(Style, string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinaryPointer exposes the type used for the data in a binary conversation
|
||||||
|
// it represents a pointer to data that is produced by the module and that
|
||||||
|
// must be parsed depending on the protocol in use
|
||||||
|
type BinaryPointer unsafe.Pointer
|
||||||
|
|
||||||
|
// BinaryConversationHandler is an interface for objects that can be used as
|
||||||
|
// conversation callbacks during PAM authentication if binary protocol is going
|
||||||
|
// to be supported.
|
||||||
|
type BinaryConversationHandler interface {
|
||||||
|
ConversationHandler
|
||||||
|
// RespondPAMBinary receives a pointer to the binary message. It's up to
|
||||||
|
// the receiver to parse it according to the protocol specifications.
|
||||||
|
// The function can return a byte array that will passed as pointer back
|
||||||
|
// to the module.
|
||||||
|
RespondPAMBinary(BinaryPointer) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
// ConversationFunc is an adapter to allow the use of ordinary functions as
|
// ConversationFunc is an adapter to allow the use of ordinary functions as
|
||||||
// conversation callbacks.
|
// conversation callbacks.
|
||||||
type ConversationFunc func(Style, string) (string, error)
|
type ConversationFunc func(Style, string) (string, error)
|
||||||
@@ -57,14 +87,29 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cbPAMConv is a wrapper for the conversation callback function.
|
// cbPAMConv is a wrapper for the conversation callback function.
|
||||||
|
//
|
||||||
//export cbPAMConv
|
//export cbPAMConv
|
||||||
func cbPAMConv(s C.int, msg *C.char, c C.uintptr_t) (*C.char, C.int) {
|
func cbPAMConv(s C.int, msg *C.char, c C.uintptr_t) (*C.char, C.int) {
|
||||||
var r string
|
var r string
|
||||||
var err error
|
var err error
|
||||||
v := cgo.Handle(c).Value()
|
v := cgo.Handle(c).Value()
|
||||||
|
style := Style(s)
|
||||||
switch cb := v.(type) {
|
switch cb := v.(type) {
|
||||||
|
case BinaryConversationHandler:
|
||||||
|
if style == BinaryPrompt {
|
||||||
|
bytes, err := cb.RespondPAMBinary(BinaryPointer(msg))
|
||||||
|
if err != nil {
|
||||||
|
return nil, C.PAM_CONV_ERR
|
||||||
|
}
|
||||||
|
return (*C.char)(C.CBytes(bytes)), C.PAM_SUCCESS
|
||||||
|
} else {
|
||||||
|
r, err = cb.RespondPAM(style, C.GoString(msg))
|
||||||
|
}
|
||||||
case ConversationHandler:
|
case ConversationHandler:
|
||||||
r, err = cb.RespondPAM(Style(s), C.GoString(msg))
|
if style == BinaryPrompt {
|
||||||
|
return nil, C.PAM_AUTHINFO_UNAVAIL
|
||||||
|
}
|
||||||
|
r, err = cb.RespondPAM(style, C.GoString(msg))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, C.PAM_CONV_ERR
|
return nil, C.PAM_CONV_ERR
|
||||||
@@ -117,6 +162,12 @@ func StartConfDir(service, user string, handler ConversationHandler, confDir str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func start(service, user string, handler ConversationHandler, confDir string) (*Transaction, error) {
|
func start(service, user string, handler ConversationHandler, confDir string) (*Transaction, error) {
|
||||||
|
switch handler.(type) {
|
||||||
|
case BinaryConversationHandler:
|
||||||
|
if !CheckPamHasBinaryProtocol() {
|
||||||
|
return nil, errors.New("BinaryConversationHandler() was used, but it is not supported by this platform")
|
||||||
|
}
|
||||||
|
}
|
||||||
t := &Transaction{
|
t := &Transaction{
|
||||||
conv: &C.struct_pam_conv{},
|
conv: &C.struct_pam_conv{},
|
||||||
c: cgo.NewHandle(handler),
|
c: cgo.NewHandle(handler),
|
||||||
@@ -339,3 +390,8 @@ func (t *Transaction) GetEnvList() (map[string]string, error) {
|
|||||||
func CheckPamHasStartConfdir() bool {
|
func CheckPamHasStartConfdir() bool {
|
||||||
return C.check_pam_start_confdir() == 0
|
return C.check_pam_start_confdir() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckPamHasBinaryProtocol return if pam on system supports PAM_BINARY_PROMPT
|
||||||
|
func CheckPamHasBinaryProtocol() bool {
|
||||||
|
return C.BINARY_PROMPT_IS_SUPPORTED != 0
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user