@@ -1010,6 +1010,64 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
1010
1010
Errno :: result ( res) . map ( drop)
1011
1011
}
1012
1012
1013
+ /// Calculate the supplementary group access list. Gets the group IDs of all
1014
+ /// groups that `user` is a member of. The additional group `group` is also
1015
+ /// added to the list.
1016
+ ///
1017
+ /// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html)
1018
+ pub fn getgrouplist ( user : & CString , group : Gid ) -> Result < Vec < Gid > > {
1019
+ let ngroups_max = match sysconf ( SysconfVar :: NGROUPS_MAX ) {
1020
+ Ok ( Some ( n) ) => n as c_int ,
1021
+ Ok ( None ) | Err ( _) => <c_int >:: max_value ( ) ,
1022
+ } ;
1023
+ use std:: cmp:: min;
1024
+ let mut ngroups = min ( ngroups_max, 8 ) ;
1025
+ let mut groups = Vec :: < Gid > :: with_capacity ( ngroups as usize ) ;
1026
+ cfg_if ! {
1027
+ if #[ cfg( any( target_os = "ios" , target_os = "macos" ) ) ] {
1028
+ type getgrouplist_group_t = c_int;
1029
+ } else {
1030
+ type getgrouplist_group_t = gid_t;
1031
+ }
1032
+ }
1033
+ let gid: gid_t = group. into ( ) ;
1034
+ loop {
1035
+ let ret = unsafe {
1036
+ libc:: getgrouplist ( user. as_ptr ( ) ,
1037
+ gid as getgrouplist_group_t ,
1038
+ groups. as_mut_ptr ( ) as * mut getgrouplist_group_t ,
1039
+ & mut ngroups)
1040
+ } ;
1041
+ // BSD systems only return 0 or -1, Linux returns ngroups on success.
1042
+ if ret >= 0 {
1043
+ unsafe { groups. set_len ( ngroups as usize ) } ;
1044
+ break
1045
+ }
1046
+
1047
+ // Returns -1 if ngroups is too small, but does not set errno.
1048
+ // BSD systems will still fill the groups buffer with as many groups
1049
+ // as possible, but Linux manpages do not mention this behavior.
1050
+ if ret == -1 {
1051
+ let cap = groups. capacity ( ) ;
1052
+ if cap >= ngroups_max as usize {
1053
+ // We already have the largest capacity we can, give up
1054
+ // FIXME: What error should be returned?
1055
+ return Err ( Error :: invalid_argument ( ) )
1056
+ }
1057
+
1058
+ // Trigger buffer resizing
1059
+ unsafe { groups. set_len ( cap) } ;
1060
+ groups. reserve ( ngroups as usize - cap) ;
1061
+
1062
+ // Even if the buffer gets resized to bigger than ngroups_max,
1063
+ // don't ever ask for more than ngroups_max groups
1064
+ ngroups = min ( ngroups_max, groups. capacity ( ) as c_int ) ;
1065
+ }
1066
+ }
1067
+
1068
+ Ok ( groups)
1069
+ }
1070
+
1013
1071
/// Initialize the supplementary group access list. Sets the supplementary
1014
1072
/// group IDs for the calling process using all groups that `user` is a member
1015
1073
/// of. The additional group `group` is also added to the list.
0 commit comments