From 1a4a020ad5766fce3b3ad719d85593a3e8159733 Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Mon, 17 Jul 2017 17:30:46 -0700 Subject: [PATCH] cmd/fscrypt: username and login token fix The commit changes how we get the username representation, and uses the new pam API for checking the proposed login token. --- cmd/fscrypt/errors.go | 2 +- cmd/fscrypt/keys.go | 11 ++++++----- cmd/fscrypt/prompt.go | 24 ++++++++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/cmd/fscrypt/errors.go b/cmd/fscrypt/errors.go index c698673..f11ff12 100644 --- a/cmd/fscrypt/errors.go +++ b/cmd/fscrypt/errors.go @@ -46,7 +46,6 @@ var ( ErrCanceled = errors.New("operation canceled") ErrNoDesctructiveOps = errors.New("operation would be destructive") ErrMaxPassphrase = util.SystemError("max passphrase length exceeded") - ErrPAMPassphrase = errors.New("incorrect login passphrase") ErrInvalidSource = errors.New("invalid source type") ErrPassphraseMismatch = errors.New("entered passphrases do not match") ErrSpecifyProtector = errors.New("multiple protectors available") @@ -59,6 +58,7 @@ var ( ErrBadOwners = errors.New("you do not own this directory") ErrNotEmptyDir = errors.New("not an empty directory") ErrNotPassphrase = errors.New("protector does not use a passphrase") + ErrUnknownUser = errors.New("unknown user") ) var loadHelpText = fmt.Sprintf("You may need to mount a linked filesystem. Run with %s for more information.", shortDisplay(verboseFlag)) diff --git a/cmd/fscrypt/keys.go b/cmd/fscrypt/keys.go index 820ddec..65360a9 100644 --- a/cmd/fscrypt/keys.go +++ b/cmd/fscrypt/keys.go @@ -125,7 +125,7 @@ func makeKeyFunc(supportRetry, shouldConfirm bool, prefix string) actions.KeyFun switch info.Source() { case metadata.SourceType_pam_passphrase: prompt := fmt.Sprintf("Enter %slogin passphrase for %s: ", - prefix, getUsername(info.UID())) + prefix, formatUsername(info.UID())) key, err := getPassphraseKey(prompt) if err != nil { return nil, err @@ -134,15 +134,16 @@ func makeKeyFunc(supportRetry, shouldConfirm bool, prefix string) actions.KeyFun // To confirm, check that the passphrase is the user's // login passphrase. if shouldConfirm { - username := getUsername(info.UID()) - ok, err := pam.IsUserLoginToken(username, key) + username, err := usernameFromID(info.UID()) if err != nil { key.Wipe() return nil, err } - if !ok { + + err = pam.IsUserLoginToken(username, key, quietFlag.Value) + if err != nil { key.Wipe() - return nil, ErrPAMPassphrase + return nil, err } } return key, nil diff --git a/cmd/fscrypt/prompt.go b/cmd/fscrypt/prompt.go index fdbef81..52f8c47 100644 --- a/cmd/fscrypt/prompt.go +++ b/cmd/fscrypt/prompt.go @@ -27,6 +27,8 @@ import ( "strconv" "strings" + "github.com/pkg/errors" + "github.com/google/fscrypt/actions" "github.com/google/fscrypt/metadata" "github.com/google/fscrypt/util" @@ -106,21 +108,31 @@ func askConfirmation(question string, defaultChoice bool, warning string) error return nil } -// getUsername returns the username for the provided UID. If the UID does not -// correspond to a user or the username is blank, "UID=" is returned. -func getUsername(uid int64) string { +// usernameFromID returns the username for the provided UID. If the UID does not +// correspond to a user or the username is blank, an error is returned. +func usernameFromID(uid int64) (string, error) { u, err := user.LookupId(strconv.Itoa(int(uid))) if err != nil || u.Username == "" { - return fmt.Sprintf("UID=%d", uid) + return "", errors.Wrapf(ErrUnknownUser, "uid %d", uid) + } + return u.Username, nil +} + +// formatUsername either returns the username for the provided UID, or a string +// containing the error for unknown UIDs. +func formatUsername(uid int64) string { + username, err := usernameFromID(uid) + if err != nil { + return fmt.Sprintf("[%v]", err) } - return u.Username + return username } // formatInfo gives a string description of metadata.ProtectorData. func formatInfo(data actions.ProtectorInfo) string { switch data.Source() { case metadata.SourceType_pam_passphrase: - return "login protector for " + getUsername(data.UID()) + return "login protector for " + formatUsername(data.UID()) case metadata.SourceType_custom_passphrase: return fmt.Sprintf("custom protector %q", data.Name()) case metadata.SourceType_raw_key: -- 2.39.5