Stop passing Go pointers to C
This commit is contained in:
@@ -2,6 +2,7 @@ language: go
|
|||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.4
|
- 1.4
|
||||||
|
- 1.5
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
30
callback.go
Normal file
30
callback.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
23
callback_test.go
Normal file
23
callback_test.go
Normal file
@@ -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")
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ int cb_pam_conv(
|
|||||||
struct cbPAMConv_return result = cbPAMConv(
|
struct cbPAMConv_return result = cbPAMConv(
|
||||||
msg[i]->msg_style,
|
msg[i]->msg_style,
|
||||||
(char *)msg[i]->msg,
|
(char *)msg[i]->msg,
|
||||||
appdata_ptr);
|
(long)appdata_ptr);
|
||||||
if (result.r1 != PAM_SUCCESS) {
|
if (result.r1 != PAM_SUCCESS) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -39,13 +39,8 @@ error:
|
|||||||
return PAM_CONV_ERR;
|
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->conv = cb_pam_conv;
|
||||||
conv->appdata_ptr = appdata_ptr;
|
conv->appdata_ptr = (void *)c;
|
||||||
return conv;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package pam
|
|||||||
//#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 +50,31 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) {
|
|||||||
return f(s, msg)
|
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
|
// Constructs a new conversation object with a given handler and a newly
|
||||||
// allocated pam_conv struct that uses this object as its appdata_ptr.
|
// allocated pam_conv struct that uses this object as its appdata_ptr.
|
||||||
func newConversation(handler ConversationHandler) (*conversation, C.int) {
|
func newConversation(handler ConversationHandler) (*C.struct_pam_conv, C.int) {
|
||||||
c := &conversation{}
|
c := cbAdd(handler)
|
||||||
c.handler = handler
|
conv := &C.struct_pam_conv{}
|
||||||
c.conv = C.make_pam_conv(unsafe.Pointer(c))
|
C.init_pam_conv(conv, C.long(c))
|
||||||
if c.conv == nil {
|
return conv, C.PAM_SUCCESS
|
||||||
return nil, C.PAM_BUF_ERR
|
|
||||||
}
|
|
||||||
return c, C.PAM_SUCCESS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go-side function for processing a single conversational message. Ultimately
|
// Go-side function for processing a single conversational message. Ultimately
|
||||||
// this calls the associated ConversationHandler's ResponsePAM callback with data
|
// this calls the associated ConversationHandler's ResponsePAM callback with data
|
||||||
// coming in from a C-side call.
|
// 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 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 {
|
if err != nil {
|
||||||
return nil, C.PAM_CONV_ERR
|
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.
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize a PAM transaction.
|
// Finalize a PAM transaction.
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start initiates a new PAM transaction. Service is treated identically to
|
// 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)
|
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)
|
runtime.SetFinalizer(t, transactionFinalizer)
|
||||||
|
|||||||
Reference in New Issue
Block a user