Skip to content

Commit b3c9311

Browse files
committed
module-transaction: Do not allow parallel conversations by default
Pam conversations per se may also run in parallel, but this implies that the application supports this. Since this normally not the case, do not create modules that may invoke the pam conversations in parallel by default, adding a mutex to protect such calls.
1 parent 149df1f commit b3c9311

File tree

4 files changed

+47
-9
lines changed

4 files changed

+47
-9
lines changed

cmd/pam-moduler/moduler.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ var (
6868
moduleBuildFlags = flag.String("build-flags", "", "comma-separated list of go build flags to use when generating the module")
6969
moduleBuildTags = flag.String("build-tags", "", "comma-separated list of build tags to use when generating the module")
7070
noMain = flag.Bool("no-main", false, "whether to add an empty main to generated file")
71+
parallelConv = flag.Bool("parallel-conv", false, "whether to support performing PAM conversations in parallel")
7172
)
7273

7374
// Usage is a replacement usage function for the flags package.
@@ -136,6 +137,7 @@ func main() {
136137
generateTags: generateTags,
137138
noMain: *noMain,
138139
typeName: *typeName,
140+
parallelConv: *parallelConv,
139141
}
140142

141143
// Print the header and package clause.
@@ -168,6 +170,7 @@ type Generator struct {
168170
generateTags []string
169171
buildFlags []string
170172
noMain bool
173+
parallelConv bool
171174
}
172175

173176
func (g *Generator) Printf(format string, args ...interface{}) {
@@ -185,6 +188,11 @@ func (g *Generator) generate() {
185188
buildTagsArg = fmt.Sprintf("-tags %s", strings.Join(g.generateTags, ","))
186189
}
187190

191+
var transactionCreator = "NewModuleTransactionInvoker"
192+
if g.parallelConv {
193+
transactionCreator = "NewModuleTransactionInvokerParallelConv"
194+
}
195+
188196
vFuncs := map[string]string{
189197
"authenticate": "Authenticate",
190198
"setcred": "SetCred",
@@ -247,7 +255,7 @@ func handlePamCall(pamh *C.pam_handle_t, flags C.int, argc C.int,
247255
return pam.Ignore
248256
}
249257
250-
mt := pam.NewModuleTransactionInvoker(pam.NativeHandle(pamh))
258+
mt := pam.%s(pam.NativeHandle(pamh))
251259
ret, err := mt.InvokeHandler(moduleFunc, pam.Flags(flags),
252260
sliceFromArgv(argc, argv))
253261
@@ -257,7 +265,7 @@ func handlePamCall(pamh *C.pam_handle_t, flags C.int, argc C.int,
257265
258266
return ret
259267
}
260-
`)
268+
`, transactionCreator)
261269

262270
for cName, goName := range vFuncs {
263271
g.Printf(`

cmd/pam-moduler/tests/integration-tester-module/integration-tester-module.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:generate go run github.com/msteinert/pam/cmd/pam-moduler -type integrationTesterModule
1+
//go:generate go run github.com/msteinert/pam/cmd/pam-moduler -type integrationTesterModule -parallel-conv
22
//go:generate go generate --skip="pam_module.go"
33

44
package main

module-transaction.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"runtime"
2222
"runtime/cgo"
23+
"sync"
2324
"sync/atomic"
2425
"unsafe"
2526
)
@@ -51,6 +52,7 @@ type ModuleHandlerFunc func(ModuleTransaction, Flags, []string) error
5152
// ModuleTransaction is the module-side handle for a PAM transaction
5253
type moduleTransaction struct {
5354
transactionBase
55+
convMutex *sync.Mutex
5456
}
5557

5658
// ModuleHandler is an interface for objects that can be used to create
@@ -71,10 +73,27 @@ type ModuleTransactionInvoker interface {
7173
InvokeHandler(handler ModuleHandlerFunc, flags Flags, args []string) (Status, error)
7274
}
7375

74-
// NewModuleTransactionInvoker allows initializing a transaction invoker from
75-
// the module side.
76+
// NewModuleTransaction allows initializing a transaction from the module side.
77+
// Conversations using this transaction can be multi-thread, but this requires
78+
// the application loading the module to support this, otherwise we may just
79+
// break their assumptions.
80+
func NewModuleTransactionParallelConv(handle NativeHandle) ModuleTransaction {
81+
return &moduleTransaction{transactionBase{handle: handle}, nil}
82+
}
83+
84+
// NewModuleTransactionInvoker allows initializing a transaction invoker from the
85+
// module side.
7686
func NewModuleTransactionInvoker(handle NativeHandle) ModuleTransactionInvoker {
77-
return &moduleTransaction{transactionBase{handle: handle}}
87+
return &moduleTransaction{transactionBase{handle: handle}, &sync.Mutex{}}
88+
}
89+
90+
// NewModuleTransactionInvokerParallelConv allows initializing a transaction invoker
91+
// from the module side.
92+
// Conversations using this transaction can be multi-thread, but this requires
93+
// the application loading the module to support this, otherwise we may just
94+
// break their assumptions.
95+
func NewModuleTransactionInvokerParallelConv(handle NativeHandle) ModuleTransactionInvoker {
96+
return &moduleTransaction{transactionBase{handle: handle}, nil}
7897
}
7998

8099
func (m *moduleTransaction) InvokeHandler(handler ModuleHandlerFunc,
@@ -467,6 +486,10 @@ func (m *moduleTransaction) startConvMultiImpl(iface moduleTransactionIface,
467486
}
468487
}
469488

489+
if m.convMutex != nil {
490+
m.convMutex.Lock()
491+
defer m.convMutex.Unlock()
492+
}
470493
var cResponses *C.struct_pam_response
471494
if err := m.handlePamStatus(
472495
iface.startConv(conv, C.int(len(requests)), cMessages, &cResponses)); err != nil {

module-transaction_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,9 @@ func Test_ModuleTransaction_InvokeHandler(t *testing.T) {
296296
}
297297
}
298298

299-
func Test_MockModuleTransaction(t *testing.T) {
299+
func testMockModuleTransaction(t *testing.T, mt *moduleTransaction) {
300300
t.Parallel()
301301

302-
mt := NewModuleTransactionInvoker(nil).(*moduleTransaction)
303-
304302
tests := map[string]struct {
305303
testFunc func(mock *mockModuleTransaction) (any, error)
306304
mockExpectations mockModuleTransactionExpectations
@@ -857,3 +855,12 @@ func Test_MockModuleTransaction(t *testing.T) {
857855
})
858856
}
859857
}
858+
859+
func Test_MockModuleTransaction(t *testing.T) {
860+
testMockModuleTransaction(t, NewModuleTransactionInvoker(nil).(*moduleTransaction))
861+
}
862+
863+
func Test_MockModuleTransactionParallelConv(t *testing.T) {
864+
testMockModuleTransaction(t,
865+
NewModuleTransactionInvokerParallelConv(nil).(*moduleTransaction))
866+
}

0 commit comments

Comments
 (0)