aboutsummaryrefslogtreecommitdiff
path: root/pam_fscrypt/run_fscrypt.go
diff options
context:
space:
mode:
Diffstat (limited to 'pam_fscrypt/run_fscrypt.go')
-rw-r--r--pam_fscrypt/run_fscrypt.go94
1 files changed, 73 insertions, 21 deletions
diff --git a/pam_fscrypt/run_fscrypt.go b/pam_fscrypt/run_fscrypt.go
index 6414d99..af9537f 100644
--- a/pam_fscrypt/run_fscrypt.go
+++ b/pam_fscrypt/run_fscrypt.go
@@ -31,10 +31,10 @@ import "C"
import (
"fmt"
"io"
- "io/ioutil"
"log"
"log/syslog"
"os"
+ "os/user"
"path/filepath"
"runtime/debug"
"unsafe"
@@ -57,13 +57,30 @@ const (
countDirectoryPermissions = 0700
countFilePermissions = 0600
countFileFormat = "%d\n"
+ // uidMin is the first UID that can be used for a regular user (as
+ // opposed to a system user or root). This value is fairly standard
+ // across Linux distros, but it can be adjusted if needed.
+ uidMin = 1000
)
-// PamFunc is used to define the various actions in the PAM module
-type PamFunc func(handle *pam.Handle, args map[string]bool) error
+// PamFunc is used to define the various actions in the PAM module.
+type PamFunc struct {
+ // Name of the function being executed
+ name string
+ // Go implementation of this function
+ impl func(handle *pam.Handle, args map[string]bool) error
+}
+
+// isSystemUser checks if a user is a system user. pam_fscrypt should never
+// need to do anything for system users since they should never have login
+// protectors. Therefore, we detect them early to avoid wasting resources.
+func isSystemUser(user *user.User) bool {
+ uid := util.AtoiOrPanic(user.Uid)
+ return uid < uidMin && uid != 0
+}
-// RunPamFunc is used to convert between the Go functions and exported C funcs.
-func RunPamFunc(f PamFunc, pamh unsafe.Pointer, argc C.int, argv **C.char) (ret C.int) {
+// Run is used to convert between the Go functions and exported C funcs.
+func (f *PamFunc) Run(pamh unsafe.Pointer, argc C.int, argv **C.char) (ret C.int) {
args := parseArgs(argc, argv)
errorWriter := setupLogging(args)
@@ -72,20 +89,27 @@ func RunPamFunc(f PamFunc, pamh unsafe.Pointer, argc C.int, argv **C.char) (ret
if r := recover(); r != nil {
ret = C.PAM_SERVICE_ERR
fmt.Fprintf(errorWriter,
- "pam func panicked: %s\nPlease open an issue.\n%s",
- r, debug.Stack())
+ "%s(%v) panicked: %s\nPlease open a bug.\n%s",
+ f.name, args, r, debug.Stack())
}
}()
+ log.Printf("%s(%v) starting", f.name, args)
handle, err := pam.NewHandle(pamh)
if err == nil {
- err = f(handle, args)
+ if isSystemUser(handle.PamUser) {
+ log.Printf("invoked for system user %q (%s), doing nothing",
+ handle.PamUser.Username, handle.PamUser.Uid)
+ err = nil
+ } else {
+ err = f.impl(handle, args)
+ }
}
if err != nil {
- fmt.Fprintf(errorWriter, "pam func failed: %s", err)
+ fmt.Fprintf(errorWriter, "%s(%v) failed: %s", f.name, args, err)
return C.PAM_SERVICE_ERR
}
- log.Print("pam func succeeded")
+ log.Printf("%s(%v) succeeded", f.name, args)
return C.PAM_SUCCESS
}
@@ -107,7 +131,7 @@ func parseArgs(argc C.int, argv **C.char) map[string]bool {
// syslog.
func setupLogging(args map[string]bool) io.Writer {
log.SetFlags(0) // Syslog already includes time data itself
- log.SetOutput(ioutil.Discard)
+ log.SetOutput(io.Discard)
if args[debugFlag] {
debugWriter, err := syslog.New(syslog.LOG_DEBUG, moduleName)
if err == nil {
@@ -117,7 +141,7 @@ func setupLogging(args map[string]bool) io.Writer {
errorWriter, err := syslog.New(syslog.LOG_ERR, moduleName)
if err != nil {
- return ioutil.Discard
+ return io.Discard
}
return errorWriter
}
@@ -126,10 +150,18 @@ func setupLogging(args map[string]bool) io.Writer {
// one exists. This protector descriptor (if found) will be cached in the pam
// data, under descriptorLabel.
func loginProtector(handle *pam.Handle) (*actions.Protector, error) {
- ctx, err := actions.NewContextFromMountpoint("/", handle.PamUser)
+ ctx, err := actions.NewContextFromMountpoint(actions.LoginProtectorMountpoint,
+ handle.PamUser)
if err != nil {
return nil, err
}
+ // Ensure that pam_fscrypt only processes metadata files owned by the
+ // user or root, even if the user is root themselves. (Normally, when
+ // fscrypt is run as root it is allowed to process all metadata files.
+ // This implements stricter behavior for pam_fscrypt.)
+ if !ctx.Config.GetAllowCrossUserMetadata() {
+ ctx.TrustedUser = handle.PamUser
+ }
// Find the user's PAM protector.
options, err := ctx.ProtectorOptions()
@@ -146,8 +178,10 @@ func loginProtector(handle *pam.Handle) (*actions.Protector, error) {
}
// policiesUsingProtector searches all the mountpoints for any policies
-// protected with the specified protector.
-func policiesUsingProtector(protector *actions.Protector) []*actions.Policy {
+// protected with the specified protector. If provisioned is true, then only
+// policies provisioned by the target user are returned; otherwise only policies
+// *not* provisioned by the target user are returned.
+func policiesUsingProtector(protector *actions.Protector, provisioned bool) []*actions.Policy {
mounts, err := filesystem.AllFilesystems()
if err != nil {
log.Print(err)
@@ -157,10 +191,14 @@ func policiesUsingProtector(protector *actions.Protector) []*actions.Policy {
var policies []*actions.Policy
for _, mount := range mounts {
// Skip mountpoints that do not use the protector.
- if _, _, err := mount.GetProtector(protector.Descriptor()); err != nil {
+ if _, _, err := mount.GetProtector(protector.Descriptor(),
+ protector.Context.TrustedUser); err != nil {
+ if _, ok := err.(*filesystem.ErrNotSetup); !ok {
+ log.Print(err)
+ }
continue
}
- policyDescriptors, err := mount.ListPolicies()
+ policyDescriptors, err := mount.ListPolicies(protector.Context.TrustedUser)
if err != nil {
log.Printf("listing policies: %s", err)
continue
@@ -176,9 +214,23 @@ func policiesUsingProtector(protector *actions.Protector) []*actions.Policy {
continue
}
- if policy.UsesProtector(protector) {
- policies = append(policies, policy)
+ if !policy.UsesProtector(protector) {
+ continue
+ }
+ if provisioned {
+ if !policy.IsProvisionedByTargetUser() {
+ log.Printf("policy %s not provisioned by %v",
+ policy.Descriptor(), ctx.TargetUser.Username)
+ continue
+ }
+ } else {
+ if policy.IsProvisionedByTargetUser() {
+ log.Printf("policy %s already provisioned by %v",
+ policy.Descriptor(), ctx.TargetUser.Username)
+ continue
+ }
}
+ policies = append(policies, policy)
}
}
return policies
@@ -186,7 +238,7 @@ func policiesUsingProtector(protector *actions.Protector) []*actions.Policy {
// AdjustCount changes the session count for the pam user by the specified
// amount. If the count file does not exist, create it as if it had a count of
-// zero. If the adjustment would be the count below zero, the count is set to
+// zero. If the adjustment would bring the count below zero, the count is set to
// zero. The value of the new count is returned. Requires root privileges.
func AdjustCount(handle *pam.Handle, delta int) (int, error) {
// Make sure the directory exists
@@ -199,7 +251,7 @@ func AdjustCount(handle *pam.Handle, delta int) (int, error) {
if err != nil {
return 0, err
}
- if err := unix.Flock(int(file.Fd()), unix.LOCK_EX); err != nil {
+ if err = unix.Flock(int(file.Fd()), unix.LOCK_EX); err != nil {
return 0, err
}
defer file.Close()