From 5c853fd7317d337ab7dc3b9bfe533a22eb713e1f Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Wed, 19 Jul 2017 15:42:31 -0700 Subject: Updated documentation and build system for PAM --- README.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 7 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index e2df8ca..4355239 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,6 @@ The following functionality is planned: * `fscrypt backup` - Manages backups of the fscrypt metadata * `fscrypt recovery` - Manages recovery keys for directories * `fscrypt cleanup` - Scans filesystem for unused policies/protectors -* A PAM module to support login passphrase changes (see below) See the example usage section below or run `fscrypt COMMAND --help` for more information about each of the commands. @@ -109,7 +108,7 @@ information about each of the commands. fscrypt has the following build dependencies: * [Go](https://golang.org/doc/install) * A C compiler (`gcc` or `clang`) -* `make` +* `make` * The [Argon2 Passphrase Hash](https://github.com/P-H-C/phc-winner-argon2) library, which can be [directly installed on Artful Ubuntu](https://packages.ubuntu.com/artful/libargon2-0-dev), @@ -155,6 +154,50 @@ fscrypt has the following runtime dependencies: The dynamic libraries are not needed if you built a static executable. +### Setting up the PAM module + +Note that to make use of the installed PAM module, your +[PAM configuration files](http://www.linux-pam.org/Linux-PAM-html/sag-configuration.html) +in `/etc/pam.d` must be modified to add fscrypt. + +#### Automatic setup on Ubuntu + +fscrypt automatically installs the +[PAM config file](https://wiki.ubuntu.com/PAMConfigFrameworkSpec) +`pam_fscrypt/config` to `/usr/share/pam-configs/fscrypt`. This file contains +reasonable defaults for the PAM module. To automatically apply these changes, +run `sudo pam-auth-update` and follow the on-screen instructions. + +#### Manual setup + +The fscrypt PAM module implements the Auth, Session, and Password +[types](http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html). + +The Password functionality of `pam_fscrypt.so` is used to automatically rewrap +a user's login protector when their unix passphrase changes. An easy way to get +the working is to add the line: +``` +password optional pam_fscrypt.so +``` +after `pam_unix.so` in `/etc/pam.d/common-password` or similar. + +The Auth and Session functionality of `pam_fscrypt.so` are used to automatically +unlock directories when logging in as a user. An easy way to get this working is +to add the line: +``` +auth optional pam_fscrypt.so +``` +after `pam_unix.so` in `/etc/pam.d/common-password` or similar, and to add the +line: +``` +session optional pam_fscrypt.so drop_caches +``` +after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The `drop_caches` +option tells fscrypt to clear the filesystem caches on session closes if some +directories were unlocked. This ensures all unlocked data is inaccessible after +session close. All the types also support the `debug` option which prints +additional debug information to the syslog. + ## Note about stability fscrypt follows [semantic versioning](http://semver.org). As such, all versions @@ -507,14 +550,25 @@ best to help. #### I changed my login passphrase, now all my directories are inaccessible -We do not currently support the changing of the login passphrase. This will -change when the appropriate module is completed. Until then, you can fix it by -first finding the necessary protector (with `fscrypt status PATH`) and then -running: +The PAM module provided by fscrypt (`pam_fscrypt.so`) should automatically +detect changes to a user's login passphrase so that they can still access their +encrypted directories. However, sometimes the login passphrase can become +desynchronized from a user's login protector. This usually happens when the PAM +passphrase is managed by an external system, if the PAM module is not installed, +or if the PAM module is not properly configured. + +To fix your login protector, you first should find the appropriate protector ID +by running `fscrypt status "/"`. Then, change the passphrase for this protector +by running: ``` -fscrypt metadata change-passphrase --protector=MOUNTPOINT:ID +fscrypt metadata change-passphrase --protector=/:ID ``` +#### Directories using my login passphrase are not automatically unlocking. + +Either the PAM module is not installed correctly, or your login passphrase +changed and things got out of sync. + #### I can still see files or filenames after running `fscrypt purge MOUNTPOINT` You need to unmount `MOUNTPOINT` to clear the necessary caches. See -- cgit v1.3 From b15792b8d7c197d84970415fd2525c51aee3996c Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Wed, 23 Aug 2017 12:29:10 -0700 Subject: Added some documentation and improved security API --- CONTRIBUTING.md | 10 ++++++++++ README.md | 4 ++-- pam/pam.go | 24 ++++++++++++++++++------ security/keyring.go | 12 ++++++++++-- 4 files changed, 40 insertions(+), 10 deletions(-) (limited to 'README.md') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7272b10..6b7be43 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,16 @@ You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. +## Reporting an Issue + +Any bugs or problems found in fscrypt should be reported though the +[Github Issue Tracker](https://github.com/google/fscrypt/issues/new). When +reporting an issue, be sure to give as much information about the problem as +possible. If reporting an issue around the fscrypt command-line tool, post the +relevant output from fscrypt, running with the `--verbose` flag. For the +pam_fscrypt module, use the `debug` flag with the module and post the relevant +parts of the syslog (at ``). + ## Code reviews All submissions, including submissions by project members, require review. We diff --git a/README.md b/README.md index 4355239..cb1a1e3 100644 --- a/README.md +++ b/README.md @@ -545,8 +545,8 @@ file for more information about singing the CLA and submitting a pull request. ## Troubleshooting In general, if you are encountering issues with fscrypt, -[open an issue](https://github.com/google/fscrypt/issues/new). We will try our -best to help. +[open an issue](https://github.com/google/fscrypt/issues/new), following the +guidelines in `CONTRIBUTING.md`. We will try our best to help. #### I changed my login passphrase, now all my directories are inaccessible diff --git a/pam/pam.go b/pam/pam.go index 804171d..3049efb 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -32,12 +32,15 @@ import ( "errors" "fmt" "unsafe" + + "github.com/google/fscrypt/security" ) // Handle wraps the C pam_handle_t type. This is used from within modules. type Handle struct { handle *C.pam_handle_t status C.int + privs *security.Privileges } // NewHandle creates a Handle from a raw pointer. @@ -105,19 +108,28 @@ func (h *Handle) GetItem(i Item) (unsafe.Pointer, error) { return data, h.err() } -// GetIDs retrieves the UID and GID of the corresponding PAM_USER. -func (h *Handle) GetIDs() (uid int, gid int, err error) { +// DropThreadPrivileges sets the effective privileges to that of the PAM user +func (h *Handle) DropThreadPrivileges() error { var pamUsername *C.char + var err error + h.status = C.pam_get_user(h.handle, &pamUsername, nil) if err = h.err(); err != nil { - return 0, 0, err + return err } - pwnam := C.getpwnam(pamUsername) if pwnam == nil { - return 0, 0, fmt.Errorf("unknown user %q", C.GoString(pamUsername)) + return fmt.Errorf("unknown user %q", C.GoString(pamUsername)) } - return int(pwnam.pw_uid), int(pwnam.pw_gid), nil + + h.privs, err = security.DropThreadPrivileges(int(pwnam.pw_uid), int(pwnam.pw_gid)) + return err +} + +// RaiseThreadPrivileges restores the original privileges that were running the +// PAM module (this is usually root). +func (h *Handle) RaiseThreadPrivileges() error { + return security.RaiseThreadPrivileges(h.privs) } func (h *Handle) err() error { diff --git a/security/keyring.go b/security/keyring.go index f75b189..28225b0 100644 --- a/security/keyring.go +++ b/security/keyring.go @@ -151,11 +151,19 @@ func getUserKeyringID() (int, error) { func keyringLink(keyID int, keyringID int) error { _, err := unix.KeyctlInt(unix.KEYCTL_LINK, keyID, keyringID, 0, 0) log.Printf("KeyctlLink(%d, %d) = %v", keyID, keyringID, err) - return errors.Wrap(ErrKeyringLink, err.Error()) + + if err != nil { + return errors.Wrap(ErrKeyringLink, err.Error()) + } + return err } func keyringUnlink(keyID int, keyringID int) error { _, err := unix.KeyctlInt(unix.KEYCTL_UNLINK, keyID, keyringID, 0, 0) log.Printf("KeyctlUnlink(%d, %d) = %v", keyID, keyringID, err) - return errors.Wrap(ErrKeyringUnlink, err.Error()) + + if err != nil { + return errors.Wrap(ErrKeyringUnlink, err.Error()) + } + return err } -- cgit v1.3 From 7fbff9a4d531e33f3d7c7e0b9871c2e19a55bace Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Wed, 23 Aug 2017 23:46:54 -0700 Subject: security: fscrypt now possesses the user keyring --- README.md | 15 ++++++++------- security/keyring.go | 7 +++++++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index cb1a1e3..342fe66 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Once all the dependencies are installed, you can get the repository by running: go get -d github.com/google/fscrypt/... ``` and then you can run `make` in `$GOPATH/github.com/google/fscrypt` to build the -executable in that directory. Running `sudo make install` installs the binary to +executable and PAM moudle in that directory. Running `sudo make install` installs the binary to `/usr/local/bin`. See the `Makefile` for instructions on how to customize the build. This includes @@ -190,13 +190,14 @@ auth optional pam_fscrypt.so after `pam_unix.so` in `/etc/pam.d/common-password` or similar, and to add the line: ``` -session optional pam_fscrypt.so drop_caches +session optional pam_fscrypt.so drop_caches lock_policies ``` -after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The `drop_caches` -option tells fscrypt to clear the filesystem caches on session closes if some -directories were unlocked. This ensures all unlocked data is inaccessible after -session close. All the types also support the `debug` option which prints -additional debug information to the syslog. +after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The +`lock_policies` option locks the directories protected with the user's login +passphrase when the last session ends. The `drop_caches` option tells fscrypt to +clear the filesystem caches when the last session closes, ensuring all the +locked data is inaccessible. All the types also support the `debug` option which +prints additional debug information to the syslog. ## Note about stability diff --git a/security/keyring.go b/security/keyring.go index 28225b0..ef56364 100644 --- a/security/keyring.go +++ b/security/keyring.go @@ -141,6 +141,13 @@ func getUserKeyringID() (int, error) { } keyringID := int(parsedID) + // For some stupid reason, a thread does not automaticaly "possess" keys + // in the user keyring. So we link it into the process keyring so that + // we will not get "permission denied" when purging or modifying keys. + if err := keyringLink(keyringID, unix.KEY_SPEC_PROCESS_KEYRING); err != nil { + return 0, err + } + keyringIDCache[euid] = keyringID return keyringID, nil } -- cgit v1.3 From 19c13e861996c3503be5b0dc5a2cecfe186b1744 Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Thu, 24 Aug 2017 00:29:54 -0700 Subject: Updated documentation for PAM module help --- CONTRIBUTING.md | 4 ++-- README.md | 9 ++++----- pam_fscrypt/pam_fscrypt.go | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'README.md') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b7be43..357661c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,8 +22,8 @@ Any bugs or problems found in fscrypt should be reported though the reporting an issue, be sure to give as much information about the problem as possible. If reporting an issue around the fscrypt command-line tool, post the relevant output from fscrypt, running with the `--verbose` flag. For the -pam_fscrypt module, use the `debug` flag with the module and post the relevant -parts of the syslog (at ``). +pam_fscrypt module, use the `debug` option with the module and post the relevant +parts of the syslog (usually at `/var/log/syslog`). ## Code reviews diff --git a/README.md b/README.md index 342fe66..2214dad 100644 --- a/README.md +++ b/README.md @@ -568,12 +568,11 @@ fscrypt metadata change-passphrase --protector=/:ID #### Directories using my login passphrase are not automatically unlocking. Either the PAM module is not installed correctly, or your login passphrase -changed and things got out of sync. +changed and things got out of sync. Another reason that these directories might +not unlock is if your session starts without password authentication. The most +common case of this is public-key ssh login. -#### I can still see files or filenames after running `fscrypt purge MOUNTPOINT` - -You need to unmount `MOUNTPOINT` to clear the necessary caches. See -`fscrypt purge --help` for more information +To trigger a password authentication event, run `su $(whoami) -c exit`. #### Getting "encryption not enabled" on an ext4 filesystem. diff --git a/pam_fscrypt/pam_fscrypt.go b/pam_fscrypt/pam_fscrypt.go index 2eecd3a..21bc779 100644 --- a/pam_fscrypt/pam_fscrypt.go +++ b/pam_fscrypt/pam_fscrypt.go @@ -78,7 +78,7 @@ func OpenSession(handle *pam.Handle, _ map[string]bool) error { // We will always clear the the AUTHTOK data defer handle.ClearData(authtokLabel) // Increment the count as we add a session - if _, err := AdjustCount(handle, 1); err != nil { + if _, err := AdjustCount(handle, +1); err != nil { return err } @@ -150,6 +150,7 @@ func OpenSession(handle *pam.Handle, _ map[string]bool) error { func CloseSession(handle *pam.Handle, args map[string]bool) error { // Only do stuff on session close when we are the last session if count, err := AdjustCount(handle, -1); err != nil || count != 0 { + log.Printf("count is %d and we are not locking", count) return err } @@ -275,7 +276,6 @@ func pam_sm_close_session(pamh unsafe.Pointer, flags, argc C.int, argv **C.char) func pam_sm_chauthtok(pamh unsafe.Pointer, flags, argc C.int, argv **C.char) C.int { // Only do rewrapping if we have both AUTHTOKs and a login protector. if pam.Flag(flags)&pam.PrelimCheck != 0 { - log.Print("no preliminary checks need to run") return C.PAM_SUCCESS } -- cgit v1.3