@@ -33,8 +33,9 @@ fn chgrp_test(args: &[&str], expected_output: &str, expected_error: &str, expect
33
33
} ) ;
34
34
}
35
35
36
+ static INIT_GROUPS : Once = Once :: new ( ) ;
36
37
static mut PRIMARY_GROUP : String = String :: new ( ) ;
37
- static INIT_PRIMARY_GROUP : Once = Once :: new ( ) ;
38
+ static mut SECONDARY_GROUP : String = String :: new ( ) ;
38
39
39
40
static mut GID1 : u32 = 0 ;
40
41
static mut GID2 : u32 = 0 ;
@@ -53,11 +54,12 @@ fn get_group_id(name: &CStr) -> u32 {
53
54
54
55
// Return two groups that the current user belongs to.
55
56
fn get_groups ( ) -> ( ( String , u32 ) , ( String , u32 ) ) {
56
- // Linux - (primary group of current user, "adm")
57
+ // Linux - (primary group of current user, a group in the supplemental group list that
58
+ // is not the primary group)
57
59
// macOS - ("staff", "admin")
58
60
let ( g1, g2) = if cfg ! ( target_os = "linux" ) {
59
61
unsafe {
60
- INIT_PRIMARY_GROUP . call_once ( || {
62
+ INIT_GROUPS . call_once ( || {
61
63
let uid = libc:: getuid ( ) ;
62
64
let pw = libc:: getpwuid ( uid) ;
63
65
if pw. is_null ( ) {
@@ -72,8 +74,63 @@ fn get_groups() -> ((String, u32), (String, u32)) {
72
74
73
75
let gr_name = CStr :: from_ptr ( ( & * gr) . gr_name ) . to_owned ( ) ;
74
76
PRIMARY_GROUP = gr_name. to_str ( ) . unwrap ( ) . to_owned ( ) ;
77
+
78
+ let mut count = libc:: getgroups ( 0 , std:: ptr:: null_mut ( ) ) ;
79
+ if count < 0 {
80
+ panic ! (
81
+ "unable to determine number of secondary groups {}" ,
82
+ io:: Error :: last_os_error( )
83
+ ) ;
84
+ }
85
+
86
+ let mut groups_ptr: * mut libc:: gid_t =
87
+ libc:: malloc ( std:: mem:: size_of :: < libc:: gid_t > ( ) * count as usize )
88
+ as * mut libc:: gid_t ;
89
+
90
+ if groups_ptr. is_null ( ) {
91
+ panic ! (
92
+ "unable to allocate memory for groups list: {}" ,
93
+ io:: Error :: last_os_error( )
94
+ ) ;
95
+ }
96
+
97
+ count = libc:: getgroups ( count, groups_ptr) ;
98
+ match count {
99
+ _ if count < 2 => panic ! ( "user must be a member of at least two groups" ) ,
100
+ -1 => panic ! (
101
+ "unable to get secondary groups: {}" ,
102
+ io:: Error :: last_os_error( )
103
+ ) ,
104
+ _ => { }
105
+ }
106
+
107
+ for _ in 0 ..count {
108
+ if groups_ptr. is_null ( ) {
109
+ panic ! ( "unable to get second group: reached end of group list" ) ;
110
+ }
111
+
112
+ // Skip over the primary_gid
113
+ if * groups_ptr == primary_gid {
114
+ groups_ptr = groups_ptr. offset ( 1 ) ;
115
+ continue ;
116
+ } else {
117
+ let second_gid = * groups_ptr;
118
+ let sec_grent = libc:: getgrgid ( second_gid) ;
119
+ if sec_grent. is_null ( ) {
120
+ panic ! ( "Unable to get group entry for secondary group id {second_gid}" ) ;
121
+ }
122
+
123
+ let sec_gr_name = CStr :: from_ptr ( ( & * sec_grent) . gr_name ) . to_owned ( ) ;
124
+ SECONDARY_GROUP = sec_gr_name. to_str ( ) . unwrap ( ) . to_owned ( ) ;
125
+ break ;
126
+ }
127
+ }
128
+ if SECONDARY_GROUP == "" {
129
+ panic ! ( "unable to find suitable secondary group" ) ;
130
+ }
75
131
} ) ;
76
- ( PRIMARY_GROUP . clone ( ) , "adm" . to_owned ( ) )
132
+
133
+ ( PRIMARY_GROUP . clone ( ) , SECONDARY_GROUP . clone ( ) )
77
134
}
78
135
} else if cfg ! ( target_os = "macos" ) {
79
136
( "staff" . to_owned ( ) , "admin" . to_owned ( ) )
0 commit comments