summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Steinert <[email protected]>2015-12-03 14:59:51 -0600
committerMichael Steinert <[email protected]>2015-12-03 14:59:51 -0600
commit8ec1202046731e0b8eaa52dc88ae9b831b5b39a7 (patch)
treed0d8dc1f1b5c8b39e9d88da5b9a3e557efa5fd0c
parent6534f23b3984c4b8f517feba04a7d65b4da3ca57 (diff)
Stop passing Go pointers to C
-rw-r--r--.travis.yml1
-rw-r--r--callback.go30
-rw-r--r--callback_test.go23
-rw-r--r--transaction.c11
-rw-r--r--transaction.go42
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)