@@ -43,30 +43,15 @@ package security
4343// cgo maps them to different Go types.
4444
4545/*
46+ #define _GNU_SOURCE // for getresuid and setresuid
4647#include <sys/types.h>
47- #include <unistd.h> // setreuid, setregid
48- #include <grp.h> // setgroups
49-
50- static int my_setreuid(uid_t ruid, uid_t euid)
51- {
52- return setreuid(ruid, euid);
53- }
54-
55- static int my_setregid(gid_t rgid, gid_t egid)
56- {
57- return setregid(rgid, egid);
58- }
59-
60- static int my_setgroups(size_t size, const gid_t *list)
61- {
62- return setgroups(size, list);
63- }
48+ #include <unistd.h> // getting and setting uids and gids
49+ #include <grp.h> // setgroups
6450*/
6551import "C"
6652
6753import (
6854 "log"
69- "os"
7055 "os/user"
7156 "syscall"
7257
@@ -75,72 +60,93 @@ import (
7560 "github.com/google/fscrypt/util"
7661)
7762
78- // SetProcessPrivileges temporarily drops the privileges of the current process
79- // to have the effective uid/gid of the target user. The privileges can be
80- // changed again with another call to SetProcessPrivileges.
81- func SetProcessPrivileges (target * user.User ) error {
82- euid := util .AtoiOrPanic (target .Uid )
83- egid := util .AtoiOrPanic (target .Gid )
84- if os .Geteuid () == euid {
85- log .Printf ("Privileges already set to %q" , target .Username )
86- return nil
87- }
88- log .Printf ("Setting privileges to %q" , target .Username )
63+ // Privileges encapulate the effective uid/gid and groups of a process.
64+ type Privileges struct {
65+ euid C.uid_t
66+ egid C.gid_t
67+ groups []C.gid_t
68+ }
8969
90- // If setting privs to root, we want to set the uid first, so we will
91- // then have the necessary permissions to perform the other actions.
92- if euid == 0 {
93- if err := setUids (- 1 , euid ); err != nil {
94- return err
95- }
96- }
97- if err := setGids (- 1 , egid ); err != nil {
98- return err
99- }
100- if err := setGroups (target ); err != nil {
101- return err
70+ // ProcessPrivileges returns the process's current effective privileges.
71+ func ProcessPrivileges () (* Privileges , error ) {
72+ ruid := C .getuid ()
73+ euid := C .geteuid ()
74+ rgid := C .getgid ()
75+ egid := C .getegid ()
76+
77+ var groups []C.gid_t
78+ n , err := C .getgroups (0 , nil )
79+ if n < 0 {
80+ return nil , err
10281 }
103- // If not setting privs to root, we want to avoid dropping the uid
104- // util the very end.
105- if euid != 0 {
106- if err := setUids (- 1 , euid ); err != nil {
107- return err
82+ // If n == 0, the user isn't in any groups, so groups == nil is fine.
83+ if n > 0 {
84+ groups = make ([]C.gid_t , n )
85+ n , err = C .getgroups (n , & groups [0 ])
86+ if n < 0 {
87+ return nil , err
10888 }
89+ groups = groups [:n ]
10990 }
110- return nil
91+ log .Printf ("Current privs (real, effective): uid=(%d,%d) gid=(%d,%d) groups=%v" ,
92+ ruid , euid , rgid , egid , groups )
93+ return & Privileges {euid , egid , groups }, nil
11194}
11295
113- func setUids ( ruid , euid int ) error {
114- res , err := C . my_setreuid ( C . uid_t ( ruid ), C . uid_t ( euid ))
115- log . Printf ( "setreuid(%d, %d) = %d (errno %v)" , ruid , euid , res , err )
116- if res == 0 {
117- return nil
96+ // UserPrivileges returns the defualt privileges for the specified user.
97+ func UserPrivileges ( user * user. User ) ( * Privileges , error ) {
98+ privs := & Privileges {
99+ euid : C . uid_t ( util . AtoiOrPanic ( user . Uid )),
100+ egid : C . gid_t ( util . AtoiOrPanic ( user . Gid )),
118101 }
119- return errors .Wrapf (err .(syscall.Errno ), "setting uids" )
102+ userGroups , err := user .GroupIds ()
103+ if err != nil {
104+ return nil , util .SystemError (err .Error ())
105+ }
106+ privs .groups = make ([]C.gid_t , len (userGroups ))
107+ for i , group := range userGroups {
108+ privs .groups [i ] = C .gid_t (util .AtoiOrPanic (group ))
109+ }
110+ return privs , nil
120111}
121112
122- func setGids (rgid , egid int ) error {
123- res , err := C .my_setregid (C .gid_t (rgid ), C .gid_t (egid ))
124- log .Printf ("setregid(%d, %d) = %d (errno %v)" , rgid , egid , res , err )
125- if res == 0 {
126- return nil
113+ // SetProcessPrivileges sets the privileges of the current process to have those
114+ // specified by privs. The original privileges can be obtained by first saving
115+ // the output of ProcessPrivileges, calling SetProcessPrivileges with the
116+ // desired privs, then calling SetProcessPrivileges with the saved privs.
117+ func SetProcessPrivileges (privs * Privileges ) error {
118+ log .Printf ("Setting euid=%d egid=%d groups=%v" , privs .euid , privs .egid , privs .groups )
119+
120+ // If setting privs as root, we need to set the euid to 0 first, so that
121+ // we will have the necessary permissions to make the other changes to
122+ // the groups/egid/euid, regardless of our original euid.
123+ C .seteuid (0 )
124+
125+ // Seperately handle the case where the user is in no groups.
126+ numGroups := C .size_t (len (privs .groups ))
127+ groupsPtr := (* C .gid_t )(nil )
128+ if numGroups > 0 {
129+ groupsPtr = & privs .groups [0 ]
127130 }
128- return errors .Wrapf (err .(syscall.Errno ), "setting gids" )
129- }
130131
131- func setGroups (target * user.User ) error {
132- groupStrings , err := target .GroupIds ()
133- if err != nil {
134- return util .SystemError (err .Error ())
132+ if res , err := C .setgroups (numGroups , groupsPtr ); res < 0 {
133+ return errors .Wrapf (err .(syscall.Errno ), "setting groups" )
134+ }
135+ if res , err := C .setegid (privs .egid ); res < 0 {
136+ return errors .Wrapf (err .(syscall.Errno ), "setting egid" )
135137 }
136- gids := make ([]C.gid_t , len (groupStrings ))
137- for i , groupString := range groupStrings {
138- gids [i ] = C .gid_t (util .AtoiOrPanic (groupString ))
138+ if res , err := C .seteuid (privs .euid ); res < 0 {
139+ return errors .Wrapf (err .(syscall.Errno ), "setting euid" )
139140 }
140- res , err := C .my_setgroups (C .size_t (len (groupStrings )), & gids [0 ])
141- log .Printf ("setgroups(%v) = %d (errno %v)" , gids , res , err )
141+ ProcessPrivileges ()
142+ return nil
143+ }
144+
145+ func setUids (ruid , euid int ) error {
146+ res , err := C .setreuid (C .uid_t (ruid ), C .uid_t (euid ))
147+ log .Printf ("setreuid(%d, %d) = %d (errno %v)" , ruid , euid , res , err )
142148 if res == 0 {
143149 return nil
144150 }
145- return errors .Wrapf (err .(syscall.Errno ), "setting groups " )
151+ return errors .Wrapf (err .(syscall.Errno ), "setting uids " )
146152}
0 commit comments