summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Trevisan (Treviño) <[email protected]>2023-09-19 20:04:06 +0200
committerMarco Trevisan (Treviño) <[email protected]>2023-09-19 20:06:38 +0200
commit78ffef4acdc2b5b6365c7167405cf72239da584a (patch)
treeb5af24a72244faeccbda6a86ea754293214560fe
parent5253f659f39e53933241047250d12d92aa173192 (diff)
transaction: Use cgo.Handle to pass callback data to PAM
Go provides a nicer way to handle Go structs lifetime when they are passed to C now, so use this instead of a custom implementation that requires to store them in a map
-rw-r--r--callback.go39
-rw-r--r--callback_test.go33
-rw-r--r--transaction.c7
-rw-r--r--transaction.go16
4 files changed, 13 insertions, 82 deletions
diff --git a/callback.go b/callback.go
deleted file mode 100644
index 672a36e..0000000
--- a/callback.go
+++ /dev/null
@@ -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)
-}
diff --git a/callback_test.go b/callback_test.go
deleted file mode 100644
index 45a84be..0000000
--- a/callback_test.go
+++ /dev/null
@@ -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")
-}
diff --git a/transaction.c b/transaction.c
index 07155e1..df25cf6 100644
--- a/transaction.c
+++ b/transaction.c
@@ -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)
diff --git a/transaction.go b/transaction.go
index c8b0960..31a6dbc 100644
--- a/transaction.go
+++ b/transaction.go
@@ -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))