1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * Ported by Wayne Boyer
4 * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2013
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 * the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * Test Description:
23 * Verify that, getgroups() system call gets the supplementary group IDs
24 * of the calling process.
25 *
26 * Expected Result:
27 * The call succeeds in getting all the supplementary group IDs of the
28 * calling process. The effective group ID may or may not be returned.
29 */
30
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <grp.h>
38 #include <sys/stat.h>
39 #include <sys/param.h>
40 #include <pwd.h>
41
42 #include "test.h"
43 #include "compat_16.h"
44
45 #define TESTUSER "root"
46
47 TCID_DEFINE(getgroups03);
48 int TST_TOTAL = 1;
49
50 static int ngroups;
51 static GID_T groups_list[NGROUPS];
52 static GID_T groups[NGROUPS];
53
54 static void verify_groups(int ret_ngroups);
55 static void setup(void);
56 static void cleanup(void);
57
main(int ac,char ** av)58 int main(int ac, char **av)
59 {
60 int lc;
61 int gidsetsize = NGROUPS;
62
63 tst_parse_opts(ac, av, NULL, NULL);
64
65 setup();
66
67 for (lc = 0; TEST_LOOPING(lc); lc++) {
68
69 tst_count = 0;
70
71 TEST(GETGROUPS(cleanup, gidsetsize, groups_list));
72
73 if (TEST_RETURN == -1) {
74 tst_resm(TFAIL | TTERRNO, "getgroups failed");
75 continue;
76 }
77
78 verify_groups(TEST_RETURN);
79 }
80
81 cleanup();
82 tst_exit();
83 }
84
85 /*
86 * readgroups(GID_T *) - Read supplimentary group ids of "root" user
87 * Scans the /etc/group file to get IDs of all the groups to which TESTUSER
88 * belongs and puts them into the array passed.
89 * Returns the no of gids read.
90 */
readgroups(GID_T groups[NGROUPS])91 static int readgroups(GID_T groups[NGROUPS])
92 {
93 struct group *grp;
94 int ngrps = 0;
95 int i;
96 int found;
97 GID_T g;
98
99 setgrent();
100
101 while ((grp = getgrent()) != 0) {
102 for (i = 0; grp->gr_mem[i]; i++) {
103 if (strcmp(grp->gr_mem[i], TESTUSER) == 0) {
104 groups[ngrps++] = grp->gr_gid;
105 }
106 }
107 }
108
109 /* The getgroups specification says:
110 It is unspecified whether the effective group ID of the
111 calling process is included in the returned list. (Thus,
112 an application should also call getegid(2) and add or
113 remove the resulting value.). So, add the value here if
114 it's not in. */
115
116 found = 0;
117 g = getegid();
118
119 for (i = 0; i < ngrps; i++) {
120 if (groups[i] == g)
121 found = 1;
122 }
123 if (found == 0)
124 groups[ngrps++] = g;
125
126 endgrent();
127 return ngrps;
128 }
129
setup(void)130 static void setup(void)
131 {
132 tst_require_root();
133
134 tst_sig(NOFORK, DEF_HANDLER, cleanup);
135
136 TEST_PAUSE;
137
138 /*
139 * Get the IDs of all the groups of "root"
140 * from /etc/group file
141 */
142 ngroups = readgroups(groups);
143
144 /* Setgroups is called by the login(1) process
145 * if the testcase is executed via an ssh session this
146 * testcase will fail. So execute setgroups() before executing
147 * getgroups()
148 */
149 if (SETGROUPS(cleanup, ngroups, groups) == -1)
150 tst_brkm(TBROK | TERRNO, cleanup, "setgroups failed");
151 }
152
153 /*
154 * verify_groups(int) - Verify supplimentary group id values.
155 * This function verifies the gid values returned by getgroups() with
156 * the read values from /etc/group file.
157 * This function returns flag value which indicates success or failure
158 * of verification.
159 */
verify_groups(int ret_ngroups)160 static void verify_groups(int ret_ngroups)
161 {
162 int i, j;
163 GID_T egid;
164 int egid_flag = 1;
165 int fflag = 1;
166
167 /*
168 * Loop through the array to verify the gids
169 * returned by getgroups().
170 * First, compare each element of the array
171 * returned by getgroups() with that read from
172 * group file.
173 */
174 for (i = 0; i < ret_ngroups; i++) {
175 for (j = 0; j < ngroups; j++) {
176 if (groups_list[i] != groups[j]) {
177 /* If loop ends and gids are not matching */
178 if (j == ngroups - 1) {
179 tst_resm(TFAIL, "getgroups returned "
180 "incorrect gid %d",
181 groups_list[i]);
182 fflag = 0;
183 } else {
184 continue;
185 }
186 } else {
187 break;
188 }
189 }
190 }
191
192 /* Now do the reverse comparison */
193 egid = getegid();
194 for (i = 0; i < ngroups; i++) {
195 for (j = 0; j < ret_ngroups; j++) {
196 if (groups[i] != groups_list[j]) {
197 /*
198 * If the loop ends & gids are not matching
199 * if gid is not egid, exit with error
200 * else egid is returned by getgroups()
201 */
202 if (j == (ret_ngroups - 1)) {
203 if (groups[i] != egid) {
204 tst_resm(TFAIL, "getgroups "
205 "didn't return %d one "
206 "of the gids of %s",
207 groups[i], TESTUSER);
208 fflag = 0;
209 } else {
210 /*
211 * egid is not present in
212 * group_list.
213 * Reset the egid flag
214 */
215 egid_flag = 0;
216 }
217 }
218 } else {
219 break;
220 }
221 }
222 }
223
224 /*
225 * getgroups() should return the no. of gids for TESTUSER with
226 * or without egid taken into account.
227 * Decrement ngroups, if egid is not returned by getgroups()
228 * Now, if ngroups matches ret_val, as above comparisons of the array
229 * are successful, this implies that the array contents match.
230 */
231 if (egid_flag == 0)
232 ngroups--;
233 if (ngroups != ret_ngroups) {
234 tst_resm(TFAIL,
235 "getgroups(2) returned incorrect no. of gids %d "
236 "(expected %d)", ret_ngroups, ngroups);
237 fflag = 0;
238 }
239
240 if (fflag)
241 tst_resm(TPASS, "getgroups functionality correct");
242 }
243
cleanup(void)244 static void cleanup(void)
245 {
246 }
247