xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/getgroups/getgroups03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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