From bc958bdbd745ac622cf332152816669cc4fb108a Mon Sep 17 00:00:00 2001 From: Didier Roche Date: Fri, 16 Sep 2022 08:09:26 +0200 Subject: [PATCH] Allow to define confdir PAM has a pam_start_confdir() which allows to define the configuration directory where all services are located. This is useful to define your own service on tests in particular, so that you can control your stack and be independant of the host when running them. Allow defining this configuration directory, with a new StartConfDir function. Also, allow pre-checking for the API availability with CheckPamHasStartConfdir(). --- transaction.c | 9 +++++++++ transaction.go | 47 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/transaction.c b/transaction.c index c8ca4d2..07155e1 100644 --- a/transaction.c +++ b/transaction.c @@ -50,3 +50,12 @@ void init_pam_conv(struct pam_conv *conv, long c) conv->conv = cb_pam_conv; conv->appdata_ptr = (void *)c; } + +// pam_start_confdir is a recent PAM api to declare a confdir (mostly for tests) +// weaken the linking dependency to detect if it’s present. +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) { + if (pam_start_confdir == NULL) + return 1; + return 0; +} diff --git a/transaction.go b/transaction.go index cda848e..c8b0960 100644 --- a/transaction.go +++ b/transaction.go @@ -6,9 +6,12 @@ package pam //#cgo CFLAGS: -Wall -std=c99 //#cgo LDFLAGS: -lpam //void init_pam_conv(struct pam_conv *conv, long c); +//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" import ( + "errors" "runtime" "strings" "unsafe" @@ -85,9 +88,33 @@ func transactionFinalizer(t *Transaction) { // Start initiates a new PAM transaction. Service is treated identically to // how pam_start treats it internally. // -// All application calls to PAM begin with Start (or StartFunc). The returned +// All application calls to PAM begin with Start*. The returned // transaction provides an interface to the remainder of the API. func Start(service, user string, handler ConversationHandler) (*Transaction, error) { + return start(service, user, handler, "") +} + +// StartFunc registers the handler func as a conversation handler. +func StartFunc(service, user string, handler func(Style, string) (string, error)) (*Transaction, error) { + return Start(service, user, ConversationFunc(handler)) +} + +// StartConfDir initiates a new PAM transaction. Service is treated identically to +// how pam_start treats it internally. +// confdir allows to define where all pam services are defined. This is used to provide +// custom paths for tests. +// +// All application calls to PAM begin with Start*. The returned +// transaction provides an interface to the remainder of the API. +func StartConfDir(service, user string, handler ConversationHandler, confDir string) (*Transaction, error) { + if !CheckPamHasStartConfdir() { + return nil, errors.New("StartConfDir() was used, but the pam version on the system is not recent enough") + } + + return start(service, user, handler, confDir) +} + +func start(service, user string, handler ConversationHandler, confDir string) (*Transaction, error) { t := &Transaction{ conv: &C.struct_pam_conv{}, c: cbAdd(handler), @@ -101,18 +128,19 @@ 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, &t.handle) + if confDir == "" { + t.status = C.pam_start(s, u, t.conv, &t.handle) + } else { + c := C.CString(confDir) + defer C.free(unsafe.Pointer(c)) + t.status = C.pam_start_confdir(s, u, t.conv, c, &t.handle) + } if t.status != C.PAM_SUCCESS { return nil, t } return t, nil } -// StartFunc registers the handler func as a conversation handler. -func StartFunc(service, user string, handler func(Style, string) (string, error)) (*Transaction, error) { - return Start(service, user, ConversationFunc(handler)) -} - func (t *Transaction) Error() string { return C.GoString(C.pam_strerror(t.handle, C.int(t.status))) } @@ -304,3 +332,8 @@ func (t *Transaction) GetEnvList() (map[string]string, error) { C.free(unsafe.Pointer(p)) return env, nil } + +// CheckPamHasStartConfdir return if pam on system supports pam_system_confdir +func CheckPamHasStartConfdir() bool { + return C.check_pam_start_confdir() == 0 +}