diff options
author | Marco Trevisan (Treviño) <[email protected]> | 2023-09-19 20:04:06 +0200 |
---|---|---|
committer | Marco Trevisan (Treviño) <[email protected]> | 2023-09-19 20:06:38 +0200 |
commit | 78ffef4acdc2b5b6365c7167405cf72239da584a (patch) | |
tree | b5af24a72244faeccbda6a86ea754293214560fe | |
parent | 5253f659f39e53933241047250d12d92aa173192 (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.go | 39 | ||||
-rw-r--r-- | callback_test.go | 33 | ||||
-rw-r--r-- | transaction.c | 7 | ||||
-rw-r--r-- | transaction.go | 16 |
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)) |