1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * Ported by Wayne Boyer
4 * Copyright (c) Cyril Hrubis <[email protected]> 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
44 /*
45 * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after
46 * rewriting all tests to the new API.
47 */
48 #include "compat_16.h"
49
50 #define TESTUSER "root"
51
52 TCID_DEFINE(getgroups03);
53 int TST_TOTAL = 1;
54
55 static int ngroups;
56 static GID_T groups_list[NGROUPS];
57 static GID_T groups[NGROUPS];
58
59 static void verify_groups(int ret_ngroups);
60 static void setup(void);
61 static void cleanup(void);
62
main(int ac,char ** av)63 int main(int ac, char **av)
64 {
65 int lc;
66 int gidsetsize = NGROUPS;
67
68 tst_parse_opts(ac, av, NULL, NULL);
69
70 setup();
71
72 for (lc = 0; TEST_LOOPING(lc); lc++) {
73
74 tst_count = 0;
75
76 TEST(GETGROUPS(cleanup, gidsetsize, groups_list));
77
78 if (TEST_RETURN == -1) {
79 tst_resm(TFAIL | TTERRNO, "getgroups failed");
80 continue;
81 }
82
83 verify_groups(TEST_RETURN);
84 }
85
86 cleanup();
87 tst_exit();
88 }
89
90 /*
91 * readgroups(GID_T *) - Read supplimentary group ids of "root" user
92 * Scans the /etc/group file to get IDs of all the groups to which TESTUSER
93 * belongs and puts them into the array passed.
94 * Returns the no of gids read.
95 */
readgroups(GID_T groups[NGROUPS])96 static int readgroups(GID_T groups[NGROUPS])
97 {
98 struct group *grp;
99 int ngrps = 0;
100 int i;
101 int found;
102 GID_T g;
103
104 setgrent();
105
106 while ((grp = getgrent()) != 0) {
107 for (i = 0; grp->gr_mem[i]; i++) {
108 if (strcmp(grp->gr_mem[i], TESTUSER) == 0) {
109 groups[ngrps++] = grp->gr_gid;
110 }
111 }
112 }
113
114 /* The getgroups specification says:
115 It is unspecified whether the effective group ID of the
116 calling process is included in the returned list. (Thus,
117 an application should also call getegid(2) and add or
118 remove the resulting value.). So, add the value here if
119 it's not in. */
120
121 found = 0;
122 g = getegid();
123
124 for (i = 0; i < ngrps; i++) {
125 if (groups[i] == g)
126 found = 1;
127 }
128 if (found == 0)
129 groups[ngrps++] = g;
130
131 endgrent();
132 return ngrps;
133 }
134
setup(void)135 static void setup(void)
136 {
137 tst_require_root();
138
139 tst_sig(NOFORK, DEF_HANDLER, cleanup);
140
141 TEST_PAUSE;
142
143 /*
144 * Get the IDs of all the groups of "root"
145 * from /etc/group file
146 */
147 ngroups = readgroups(groups);
148
149 /* Setgroups is called by the login(1) process
150 * if the testcase is executed via an ssh session this
151 * testcase will fail. So execute setgroups() before executing
152 * getgroups()
153 */
154 if (SETGROUPS(cleanup, ngroups, groups) == -1)
155 tst_brkm(TBROK | TERRNO, cleanup, "setgroups failed");
156 }
157
158 /*
159 * verify_groups(int) - Verify supplimentary group id values.
160 * This function verifies the gid values returned by getgroups() with
161 * the read values from /etc/group file.
162 * This function returns flag value which indicates success or failure
163 * of verification.
164 */
verify_groups(int ret_ngroups)165 static void verify_groups(int ret_ngroups)
166 {
167 int i, j;
168 GID_T egid;
169 int egid_flag = 1;
170 int fflag = 1;
171
172 /*
173 * Loop through the array to verify the gids
174 * returned by getgroups().
175 * First, compare each element of the array
176 * returned by getgroups() with that read from
177 * group file.
178 */
179 for (i = 0; i < ret_ngroups; i++) {
180 for (j = 0; j < ngroups; j++) {
181 if (groups_list[i] != groups[j]) {
182 /* If loop ends and gids are not matching */
183 if (j == ngroups - 1) {
184 tst_resm(TFAIL, "getgroups returned "
185 "incorrect gid %d",
186 groups_list[i]);
187 fflag = 0;
188 } else {
189 continue;
190 }
191 } else {
192 break;
193 }
194 }
195 }
196
197 /* Now do the reverse comparison */
198 egid = getegid();
199 for (i = 0; i < ngroups; i++) {
200 for (j = 0; j < ret_ngroups; j++) {
201 if (groups[i] != groups_list[j]) {
202 /*
203 * If the loop ends & gids are not matching
204 * if gid is not egid, exit with error
205 * else egid is returned by getgroups()
206 */
207 if (j == (ret_ngroups - 1)) {
208 if (groups[i] != egid) {
209 tst_resm(TFAIL, "getgroups "
210 "didn't return %d one "
211 "of the gids of %s",
212 groups[i], TESTUSER);
213 fflag = 0;
214 } else {
215 /*
216 * egid is not present in
217 * group_list.
218 * Reset the egid flag
219 */
220 egid_flag = 0;
221 }
222 }
223 } else {
224 break;
225 }
226 }
227 }
228
229 /*
230 * getgroups() should return the no. of gids for TESTUSER with
231 * or without egid taken into account.
232 * Decrement ngroups, if egid is not returned by getgroups()
233 * Now, if ngroups matches ret_val, as above comparisons of the array
234 * are successful, this implies that the array contents match.
235 */
236 if (egid_flag == 0)
237 ngroups--;
238 if (ngroups != ret_ngroups) {
239 tst_resm(TFAIL,
240 "getgroups(2) returned incorrect no. of gids %d "
241 "(expected %d)", ret_ngroups, ngroups);
242 fflag = 0;
243 }
244
245 if (fflag)
246 tst_resm(TPASS, "getgroups functionality correct");
247 }
248
cleanup(void)249 static void cleanup(void)
250 {
251 }
252