|
|
@ -1,10 +1,11 @@ |
|
|
|
|
|
|
|
// Package pam provides a wrapper for the PAM application API.
|
|
|
|
package pam |
|
|
|
package pam |
|
|
|
|
|
|
|
|
|
|
|
//#include <security/pam_appl.h>
|
|
|
|
//#include <security/pam_appl.h>
|
|
|
|
//#include <stdlib.h>
|
|
|
|
//#include <stdlib.h>
|
|
|
|
//#cgo CFLAGS: -Wall -std=c99
|
|
|
|
//#cgo CFLAGS: -Wall -std=c99
|
|
|
|
//#cgo LDFLAGS: -lpam
|
|
|
|
//#cgo LDFLAGS: -lpam
|
|
|
|
//struct pam_conv *make_pam_conv(void *);
|
|
|
|
//void init_pam_conv(struct pam_conv *conv, long c);
|
|
|
|
import "C" |
|
|
|
import "C" |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
@ -50,31 +51,16 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) { |
|
|
|
return f(s, msg) |
|
|
|
return f(s, msg) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Internal conversation structure
|
|
|
|
// cbPAMConv is a wrapper for the conversation callback function.
|
|
|
|
type conversation struct { |
|
|
|
|
|
|
|
handler ConversationHandler |
|
|
|
|
|
|
|
conv *C.struct_pam_conv |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Constructs a new conversation object with a given handler and a newly
|
|
|
|
|
|
|
|
// allocated pam_conv struct that uses this object as its appdata_ptr.
|
|
|
|
|
|
|
|
func newConversation(handler ConversationHandler) (*conversation, C.int) { |
|
|
|
|
|
|
|
c := &conversation{} |
|
|
|
|
|
|
|
c.handler = handler |
|
|
|
|
|
|
|
c.conv = C.make_pam_conv(unsafe.Pointer(c)) |
|
|
|
|
|
|
|
if c.conv == nil { |
|
|
|
|
|
|
|
return nil, C.PAM_BUF_ERR |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return c, C.PAM_SUCCESS |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Go-side function for processing a single conversational message. Ultimately
|
|
|
|
|
|
|
|
// this calls the associated ConversationHandler's ResponsePAM callback with data
|
|
|
|
|
|
|
|
// coming in from a C-side call.
|
|
|
|
|
|
|
|
//export cbPAMConv
|
|
|
|
//export cbPAMConv
|
|
|
|
func cbPAMConv(s C.int, msg *C.char, appdata unsafe.Pointer) (*C.char, C.int) { |
|
|
|
func cbPAMConv(s C.int, msg *C.char, c int) (*C.char, C.int) { |
|
|
|
c := (*conversation)(appdata) |
|
|
|
var r string |
|
|
|
r, err := c.handler.RespondPAM(Style(s), C.GoString(msg)) |
|
|
|
var err error |
|
|
|
|
|
|
|
v := cbGet(c) |
|
|
|
|
|
|
|
switch cb := v.(type) { |
|
|
|
|
|
|
|
case ConversationHandler: |
|
|
|
|
|
|
|
r, err = cb.RespondPAM(Style(s), C.GoString(msg)) |
|
|
|
|
|
|
|
} |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, C.PAM_CONV_ERR |
|
|
|
return nil, C.PAM_CONV_ERR |
|
|
|
} |
|
|
|
} |
|
|
@ -84,14 +70,16 @@ func cbPAMConv(s C.int, msg *C.char, appdata unsafe.Pointer) (*C.char, C.int) { |
|
|
|
// Transaction is the application's handle for a PAM transaction.
|
|
|
|
// Transaction is the application's handle for a PAM transaction.
|
|
|
|
type Transaction struct { |
|
|
|
type Transaction struct { |
|
|
|
handle *C.pam_handle_t |
|
|
|
handle *C.pam_handle_t |
|
|
|
conv *conversation |
|
|
|
conv *C.struct_pam_conv |
|
|
|
status C.int |
|
|
|
status C.int |
|
|
|
|
|
|
|
c int |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Finalize a PAM transaction.
|
|
|
|
// transactionFinalizer cleans up the PAM handle and deletes the callback
|
|
|
|
|
|
|
|
// function.
|
|
|
|
func transactionFinalizer(t *Transaction) { |
|
|
|
func transactionFinalizer(t *Transaction) { |
|
|
|
C.pam_end(t.handle, t.status) |
|
|
|
C.pam_end(t.handle, t.status) |
|
|
|
C.free(unsafe.Pointer(t.conv.conv)) |
|
|
|
cbDelete(t.c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Start initiates a new PAM transaction. Service is treated identically to
|
|
|
|
// Start initiates a new PAM transaction. Service is treated identically to
|
|
|
@ -100,11 +88,12 @@ func transactionFinalizer(t *Transaction) { |
|
|
|
// All application calls to PAM begin with Start (or StartFunc). The returned
|
|
|
|
// All application calls to PAM begin with Start (or StartFunc). The returned
|
|
|
|
// transaction provides an interface to the remainder of the API.
|
|
|
|
// transaction provides an interface to the remainder of the API.
|
|
|
|
func Start(service, user string, handler ConversationHandler) (*Transaction, error) { |
|
|
|
func Start(service, user string, handler ConversationHandler) (*Transaction, error) { |
|
|
|
t := &Transaction{} |
|
|
|
t := &Transaction{ |
|
|
|
t.conv, t.status = newConversation(handler) |
|
|
|
conv: &C.struct_pam_conv{}, |
|
|
|
if t.status != C.PAM_SUCCESS { |
|
|
|
c: cbAdd(handler), |
|
|
|
return nil, t |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
C.init_pam_conv(t.conv, C.long(t.c)) |
|
|
|
|
|
|
|
runtime.SetFinalizer(t, transactionFinalizer) |
|
|
|
s := C.CString(service) |
|
|
|
s := C.CString(service) |
|
|
|
defer C.free(unsafe.Pointer(s)) |
|
|
|
defer C.free(unsafe.Pointer(s)) |
|
|
|
var u *C.char |
|
|
|
var u *C.char |
|
|
@ -112,12 +101,10 @@ func Start(service, user string, handler ConversationHandler) (*Transaction, err |
|
|
|
u = C.CString(user) |
|
|
|
u = C.CString(user) |
|
|
|
defer C.free(unsafe.Pointer(u)) |
|
|
|
defer C.free(unsafe.Pointer(u)) |
|
|
|
} |
|
|
|
} |
|
|
|
t.status = C.pam_start(s, u, t.conv.conv, &t.handle) |
|
|
|
t.status = C.pam_start(s, u, t.conv, &t.handle) |
|
|
|
if t.status != C.PAM_SUCCESS { |
|
|
|
if t.status != C.PAM_SUCCESS { |
|
|
|
C.free(unsafe.Pointer(t.conv.conv)) |
|
|
|
|
|
|
|
return nil, t |
|
|
|
return nil, t |
|
|
|
} |
|
|
|
} |
|
|
|
runtime.SetFinalizer(t, transactionFinalizer) |
|
|
|
|
|
|
|
return t, nil |
|
|
|
return t, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|