summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDidier Roche <[email protected]>2022-09-16 08:09:26 +0200
committerDidier Roche <[email protected]>2022-09-16 08:09:26 +0200
commitbc958bdbd745ac622cf332152816669cc4fb108a (patch)
tree206196a2278afe6c0626e76b567da786836fa1b8
parentf401703daf29acc07acb7d078755f4eb0bcd6e8c (diff)
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().
-rw-r--r--transaction.c9
-rw-r--r--transaction.go47
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
+}