Merge pull request #5 from didrocks/start_confdir
Allow to define confdir
This commit is contained in:
2
my-service
Normal file
2
my-service
Normal file
@@ -0,0 +1,2 @@
|
||||
# Custom stack to always permit, independent of the user name/pass
|
||||
auth required pam_permit.so
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -166,6 +166,50 @@ func TestPAM_007(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPAM_ConfDir(t *testing.T) {
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
}
|
||||
c := Credentials{
|
||||
// the custom service always permits even with wrong password.
|
||||
Password: "wrongsecret",
|
||||
}
|
||||
tx, err := StartConfDir("my-service", "test", c, ".")
|
||||
if !CheckPamHasStartConfdir() {
|
||||
if err == nil {
|
||||
t.Fatalf("start should have errored out as pam_start_confdir is not available: %v", err)
|
||||
}
|
||||
// nothing else we do, we don't support it.
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("start #error: %v", err)
|
||||
}
|
||||
err = tx.Authenticate(0)
|
||||
if err != nil {
|
||||
t.Fatalf("authenticate #error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPAM_ConfDir_FailNoServiceOrUnsupported(t *testing.T) {
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
}
|
||||
c := Credentials{
|
||||
Password: "secret",
|
||||
}
|
||||
_, err := StartConfDir("does-not-exists", "test", c, ".")
|
||||
if err == nil {
|
||||
t.Fatalf("authenticate #expected an error")
|
||||
}
|
||||
s := err.Error()
|
||||
if len(s) == 0 {
|
||||
t.Fatalf("error #expected an error message")
|
||||
}
|
||||
}
|
||||
|
||||
func TestItem(t *testing.T) {
|
||||
tx, _ := StartFunc("passwd", "test", func(s Style, msg string) (string, error) {
|
||||
return "", nil
|
||||
|
||||
Reference in New Issue
Block a user