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