diff options
author | Michael Steinert <[email protected]> | 2015-12-03 14:59:51 -0600 |
---|---|---|
committer | Michael Steinert <[email protected]> | 2015-12-03 14:59:51 -0600 |
commit | 8ec1202046731e0b8eaa52dc88ae9b831b5b39a7 (patch) | |
tree | d0d8dc1f1b5c8b39e9d88da5b9a3e557efa5fd0c | |
parent | 6534f23b3984c4b8f517feba04a7d65b4da3ca57 (diff) |
Stop passing Go pointers to C
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | callback.go | 30 | ||||
-rw-r--r-- | callback_test.go | 23 | ||||
-rw-r--r-- | transaction.c | 11 | ||||
-rw-r--r-- | transaction.go | 42 |
5 files changed, 77 insertions, 30 deletions
diff --git a/.travis.yml b/.travis.yml index 385cb91..f48afdc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: go go: - 1.4 + - 1.5 - tip before_install: diff --git a/callback.go b/callback.go new file mode 100644 index 0000000..f2d7210 --- /dev/null +++ b/callback.go @@ -0,0 +1,30 @@ +package pam + +import "sync" + +var cb struct { + sync.Mutex + m map[int]interface{} + c int +} + +func cbAdd(v interface{}) int { + cb.Lock() + defer cb.Unlock() + if cb.m == nil { + cb.m = make(map[int]interface{}) + } + cb.c++ + cb.m[cb.c] = v + return cb.c +} + +func cbGet(c int) interface{} { + cb.Lock() + defer cb.Unlock() + v := cb.m[c] + if v == nil { + panic("Callback pointer not found") + } + return v +} diff --git a/callback_test.go b/callback_test.go new file mode 100644 index 0000000..ae1eefe --- /dev/null +++ b/callback_test.go @@ -0,0 +1,23 @@ +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") + } +} + +func TestCallback_002(t *testing.T) { + defer func() { + recover() + }() + c := cbAdd(TestCallback_002) + cbGet(c + 1) + t.Error("Expected a panic") +} diff --git a/transaction.c b/transaction.c index 4ff649b..5cf22a5 100644 --- a/transaction.c +++ b/transaction.c @@ -19,7 +19,7 @@ int cb_pam_conv( struct cbPAMConv_return result = cbPAMConv( msg[i]->msg_style, (char *)msg[i]->msg, - appdata_ptr); + (long)appdata_ptr); if (result.r1 != PAM_SUCCESS) { goto error; } @@ -39,13 +39,8 @@ error: return PAM_CONV_ERR; } -struct pam_conv *make_pam_conv(void *appdata_ptr) +void init_pam_conv(struct pam_conv *conv, long c) { - struct pam_conv* conv = malloc(sizeof *conv); - if (!conv) { - return NULL; - } conv->conv = cb_pam_conv; - conv->appdata_ptr = appdata_ptr; - return conv; + conv->appdata_ptr = (void *)c; } diff --git a/transaction.go b/transaction.go index 360d89a..f136abd 100644 --- a/transaction.go +++ b/transaction.go @@ -4,7 +4,7 @@ package pam //#include <stdlib.h> //#cgo CFLAGS: -Wall -std=c99 //#cgo LDFLAGS: -lpam -//struct pam_conv *make_pam_conv(void *); +//void init_pam_conv(struct pam_conv *conv, long c); import "C" import ( @@ -50,31 +50,31 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) { return f(s, msg) } -// Internal conversation structure -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 +func newConversation(handler ConversationHandler) (*C.struct_pam_conv, C.int) { + c := cbAdd(handler) + conv := &C.struct_pam_conv{} + C.init_pam_conv(conv, C.long(c)) + return conv, 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 -func cbPAMConv(s C.int, msg *C.char, appdata unsafe.Pointer) (*C.char, C.int) { - c := (*conversation)(appdata) - r, err := c.handler.RespondPAM(Style(s), C.GoString(msg)) +func cbPAMConv(s C.int, msg *C.char, c int) (*C.char, C.int) { + var r string + var err error + v := cbGet(c) + switch cb := v.(type) { + case ConversationFunc: + r, err = cb(Style(s), C.GoString(msg)) + case ConversationHandler: + r, err = cb.RespondPAM(Style(s), C.GoString(msg)) + default: + return nil, C.PAM_CONV_ERR + } if err != nil { return nil, C.PAM_CONV_ERR } @@ -84,14 +84,13 @@ 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. type Transaction struct { handle *C.pam_handle_t - conv *conversation + conv *C.struct_pam_conv status C.int } // Finalize a PAM transaction. func transactionFinalizer(t *Transaction) { C.pam_end(t.handle, t.status) - C.free(unsafe.Pointer(t.conv.conv)) } // Start initiates a new PAM transaction. Service is treated identically to @@ -112,9 +111,8 @@ func Start(service, user string, handler ConversationHandler) (*Transaction, err u = C.CString(user) 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 { - C.free(unsafe.Pointer(t.conv.conv)) return nil, t } runtime.SetFinalizer(t, transactionFinalizer) |