aboutsummaryrefslogtreecommitdiff
path: root/security/privileges.go
diff options
context:
space:
mode:
authorJoseph Richey <joerichey@google.com>2017-08-31 14:51:55 -0700
committerGitHub <noreply@github.com>2017-08-31 14:51:55 -0700
commitb04d7ef31dc2e21f055b1b656efb9511e72db6c6 (patch)
tree04daee42d94ddda55d956e72f44bafec0ef6dde1 /security/privileges.go
parent5285a8c451ef660f932e9f1823ad7da52ad25b74 (diff)
parentf1bd511fff8e411687001bd8e76e8a41c9f5ff41 (diff)
Merge pull request #52 from google/keyrings
Changes to the keyrings interface, corresponding UI changes, and misc changes
Diffstat (limited to 'security/privileges.go')
-rw-r--r--security/privileges.go140
1 files changed, 57 insertions, 83 deletions
diff --git a/security/privileges.go b/security/privileges.go
index aff41a7..2a1bdae 100644
--- a/security/privileges.go
+++ b/security/privileges.go
@@ -1,5 +1,5 @@
/*
- * privileges.go - Handles raising and dropping user privileges.
+ * privileges.go - Functions for managing users and privileges.
*
* Copyright 2017 Google Inc.
* Author: Joe Richey (joerichey@google.com)
@@ -26,6 +26,7 @@ package security
import (
"log"
+ "os/user"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
@@ -33,101 +34,74 @@ import (
"github.com/google/fscrypt/util"
)
-// Package security error values
-var (
- ErrReadingKeyList = util.SystemError("could not read keys from " + keyListFilename)
- ErrFindingKeyring = util.SystemError("could not find user keyring")
- ErrKeyringInsert = util.SystemError("could not insert key into the keyring")
- ErrKeyringSearch = errors.New("could not find key with descriptor")
- ErrKeyringDelete = util.SystemError("could not delete key from the keyring")
- ErrKeyringLink = util.SystemError("could not link keyring")
- ErrKeyringUnlink = util.SystemError("could not unlink keyring")
-)
-
-// Privileges contains the state needed to restore a user's original privileges.
-type Privileges struct {
- euid int
- egid int
- groups []int
-}
-
-// DropThreadPrivileges temporarily drops the privileges of the current thread
-// to have the euid and egid specified. The returned opaque Privileges structure
-// should later be passed to RestoreThreadPrivileges.
-// Due to golang/go#1435, these privileges are only dropped for a single thread.
-// This function also makes sure that the appropriate user keyrings are linked.
-// This ensures that the user's keys are visible from commands like sudo.
-func DropThreadPrivileges(euid int, egid int) (privs *Privileges, err error) {
- privs = &Privileges{
- euid: unix.Geteuid(),
- egid: unix.Getegid(),
- }
- if privs.groups, err = unix.Getgroups(); err != nil {
- return nil, errors.Wrapf(err, "getting groups")
+// SetThreadPrivileges drops drops the privileges of the current thread to have
+// the uid/gid of the target user. If permanent is true, this operation cannot
+// be reversed in the thread (the real and effective IDs are set). If
+// permanent is false, only the effective IDs are set, allowing the privileges
+// to be changed again with another call to SetThreadPrivileges.
+func SetThreadPrivileges(target *user.User, permanent bool) error {
+ euid := util.AtoiOrPanic(target.Uid)
+ egid := util.AtoiOrPanic(target.Gid)
+ var ruid, rgid int
+ if permanent {
+ log.Printf("Permanently dropping to user %q", target.Username)
+ ruid, rgid = euid, egid
+ } else {
+ log.Printf("Temporarily dropping to user %q", target.Username)
+ // Real IDs of -1 mean they will not be changed.
+ ruid, rgid = -1, -1
}
- // We link the privileged keyring into the thread keyring so that we
- // can still modify it after dropping privileges.
- privilegedUserKeyringID, err := getUserKeyringID()
- if err != nil {
- return
- }
- if err = keyringLink(privilegedUserKeyringID, unix.KEY_SPEC_THREAD_KEYRING); err != nil {
- return
+ // If setting privs to root, we want to set the uid first, so we will
+ // then have the necessary permissions to perform the other actions.
+ if euid == 0 {
+ if err := setUids(ruid, euid); err != nil {
+ return err
+ }
}
- defer keyringUnlink(privilegedUserKeyringID, unix.KEY_SPEC_THREAD_KEYRING)
- // Drop euid last so we have permissions to drop the others.
- if err = unix.Setregid(-1, egid); err != nil {
- err = errors.Wrapf(err, "dropping egid to %d", egid)
- return
- }
- if err = unix.Setgroups([]int{egid}); err != nil {
- err = errors.Wrapf(err, "dropping groups")
- return
+ if err := setGids(rgid, egid); err != nil {
+ return err
}
- if err = unix.Setreuid(-1, euid); err != nil {
- err = errors.Wrapf(err, "dropping euid to %d", euid)
- return
+
+ if err := setGroups(target); err != nil {
+ return err
}
- log.Printf("privileges dropped to euid=%d, egid=%d", euid, egid)
- // Failure should undo the privilege modification
- defer func() {
- if err != nil {
- raiseErr := RaiseThreadPrivileges(privs)
- log.Printf("when reverting privilege changes: %v", raiseErr)
+ // If not setting privs to root, we want to avoid dropping the uid
+ // util the very end.
+ if euid != 0 {
+ if err := setUids(ruid, euid); err != nil {
+ return err
}
- }()
-
- // If the link already exists, this linking does nothing and succeeds.
- droppedUserKeyringID, err := getUserKeyringID()
- if err != nil {
- return
- }
- if err = keyringLink(droppedUserKeyringID, privilegedUserKeyringID); err != nil {
- return
}
- log.Printf("user keyring (%d) linked into root user keyring (%d)",
- droppedUserKeyringID, privilegedUserKeyringID)
+ return nil
+}
- return privs, nil
+func setUids(ruid, euid int) error {
+ err := unix.Setreuid(ruid, euid)
+ log.Printf("Setreuid(%d, %d) = %v", ruid, euid, err)
+ return errors.Wrapf(err, "setting uids")
}
-// RaiseThreadPrivileges returns the state of a threads privileges to what it
-// was before the call to DropThreadPrivileges.
-func RaiseThreadPrivileges(privs *Privileges) error {
- // Raise euid last so we have permissions to raise the others.
- if err := unix.Setreuid(-1, privs.euid); err != nil {
- return errors.Wrapf(err, "raising euid to %d", privs.euid)
- }
- if err := unix.Setregid(-1, privs.egid); err != nil {
- return errors.Wrapf(err, "raising egid to %d", privs.egid)
+func setGids(rgid, egid int) error {
+ err := unix.Setregid(rgid, egid)
+ log.Printf("Setregid(%d, %d) = %v", rgid, egid, err)
+ return errors.Wrapf(err, "setting gids")
+}
+
+func setGroups(target *user.User) error {
+ groupStrings, err := target.GroupIds()
+ if err != nil {
+ return util.SystemError(err.Error())
}
- if err := unix.Setgroups(privs.groups); err != nil {
- return errors.Wrapf(err, "raising groups")
+
+ gids := make([]int, len(groupStrings))
+ for i, groupString := range groupStrings {
+ gids[i] = util.AtoiOrPanic(groupString)
}
- log.Printf("privileges raised to euid=%d, egid=%d", privs.euid, privs.egid)
- return nil
+ err = unix.Setgroups(gids)
+ log.Printf("Setgroups(%v) = %v", gids, err)
+ return errors.Wrapf(err, "setting groups")
}