diff options
Diffstat (limited to 'pam_fscrypt/run_fscrypt.go')
| -rw-r--r-- | pam_fscrypt/run_fscrypt.go | 94 |
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() |