Merge pull request #8 from 3v1n0/simpler-callbacks
transaction: Use cgo.Handle to pass callback data to PAM
This commit is contained in:
39
callback.go
39
callback.go
@@ -1,39 +0,0 @@
|
||||
package pam
|
||||
|
||||
import "sync"
|
||||
|
||||
var cb struct {
|
||||
sync.Mutex
|
||||
m map[int]interface{}
|
||||
c int
|
||||
}
|
||||
|
||||
func init() {
|
||||
cb.m = make(map[int]interface{})
|
||||
}
|
||||
|
||||
func cbAdd(v interface{}) int {
|
||||
cb.Lock()
|
||||
defer cb.Unlock()
|
||||
cb.c++
|
||||
cb.m[cb.c] = v
|
||||
return cb.c
|
||||
}
|
||||
|
||||
func cbGet(c int) interface{} {
|
||||
cb.Lock()
|
||||
defer cb.Unlock()
|
||||
if v, ok := cb.m[c]; ok {
|
||||
return v
|
||||
}
|
||||
panic("Callback pointer not found")
|
||||
}
|
||||
|
||||
func cbDelete(c int) {
|
||||
cb.Lock()
|
||||
defer cb.Unlock()
|
||||
if _, ok := cb.m[c]; !ok {
|
||||
panic("Callback pointer not found")
|
||||
}
|
||||
delete(cb.m, c)
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package pam
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCallback_001(t *testing.T) {
|
||||
c := cbAdd(TestCallback_001)
|
||||
v := cbGet(c)
|
||||
if reflect.TypeOf(v) != reflect.TypeOf(TestCallback_001) {
|
||||
t.Error("Received unexpected value")
|
||||
}
|
||||
cbDelete(c)
|
||||
}
|
||||
|
||||
func TestCallback_002(t *testing.T) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
c := cbAdd(TestCallback_002)
|
||||
cbGet(c + 1)
|
||||
t.Error("Expected a panic")
|
||||
}
|
||||
|
||||
func TestCallback_003(t *testing.T) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
c := cbAdd(TestCallback_003)
|
||||
cbDelete(c + 1)
|
||||
t.Error("Expected a panic")
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "_cgo_export.h"
|
||||
#include <security/pam_appl.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __sun
|
||||
@@ -25,7 +26,7 @@ int cb_pam_conv(
|
||||
struct cbPAMConv_return result = cbPAMConv(
|
||||
msg[i]->msg_style,
|
||||
(char *)msg[i]->msg,
|
||||
(long)appdata_ptr);
|
||||
(uintptr_t)appdata_ptr);
|
||||
if (result.r1 != PAM_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
@@ -45,10 +46,10 @@ error:
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
void init_pam_conv(struct pam_conv *conv, long c)
|
||||
void init_pam_conv(struct pam_conv *conv, uintptr_t appdata)
|
||||
{
|
||||
conv->conv = cb_pam_conv;
|
||||
conv->appdata_ptr = (void *)c;
|
||||
conv->appdata_ptr = (void *)appdata;
|
||||
}
|
||||
|
||||
// pam_start_confdir is a recent PAM api to declare a confdir (mostly for tests)
|
||||
|
||||
@@ -3,9 +3,10 @@ package pam
|
||||
|
||||
//#include <security/pam_appl.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <stdint.h>
|
||||
//#cgo CFLAGS: -Wall -std=c99
|
||||
//#cgo LDFLAGS: -lpam
|
||||
//void init_pam_conv(struct pam_conv *conv, long c);
|
||||
//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 check_pam_start_confdir(void);
|
||||
import "C"
|
||||
@@ -13,6 +14,7 @@ import "C"
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"runtime/cgo"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -56,10 +58,10 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) {
|
||||
|
||||
// cbPAMConv is a wrapper for the conversation callback function.
|
||||
//export cbPAMConv
|
||||
func cbPAMConv(s C.int, msg *C.char, c int) (*C.char, C.int) {
|
||||
func cbPAMConv(s C.int, msg *C.char, c C.uintptr_t) (*C.char, C.int) {
|
||||
var r string
|
||||
var err error
|
||||
v := cbGet(c)
|
||||
v := cgo.Handle(c).Value()
|
||||
switch cb := v.(type) {
|
||||
case ConversationHandler:
|
||||
r, err = cb.RespondPAM(Style(s), C.GoString(msg))
|
||||
@@ -75,14 +77,14 @@ type Transaction struct {
|
||||
handle *C.pam_handle_t
|
||||
conv *C.struct_pam_conv
|
||||
status C.int
|
||||
c int
|
||||
c cgo.Handle
|
||||
}
|
||||
|
||||
// transactionFinalizer cleans up the PAM handle and deletes the callback
|
||||
// function.
|
||||
func transactionFinalizer(t *Transaction) {
|
||||
C.pam_end(t.handle, t.status)
|
||||
cbDelete(t.c)
|
||||
t.c.Delete()
|
||||
}
|
||||
|
||||
// Start initiates a new PAM transaction. Service is treated identically to
|
||||
@@ -117,9 +119,9 @@ func StartConfDir(service, user string, handler ConversationHandler, confDir str
|
||||
func start(service, user string, handler ConversationHandler, confDir string) (*Transaction, error) {
|
||||
t := &Transaction{
|
||||
conv: &C.struct_pam_conv{},
|
||||
c: cbAdd(handler),
|
||||
c: cgo.NewHandle(handler),
|
||||
}
|
||||
C.init_pam_conv(t.conv, C.long(t.c))
|
||||
C.init_pam_conv(t.conv, C.uintptr_t(t.c))
|
||||
runtime.SetFinalizer(t, transactionFinalizer)
|
||||
s := C.CString(service)
|
||||
defer C.free(unsafe.Pointer(s))
|
||||
|
||||
Reference in New Issue
Block a user