1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Ported by John George
19 */
20
21 /*
22 * Test setregid() when executed by a non-root user.
23 */
24
25 #include <errno.h>
26 #include <grp.h>
27 #include <stdlib.h>
28 #include <pwd.h>
29 #include <string.h>
30 #include <sys/wait.h>
31
32 #include "test.h"
33 #include "compat_16.h"
34
35 TCID_DEFINE(setregid03);
36 static int fail = -1;
37 static int pass;
38 static gid_t neg_one = -1;
39
40 /* flag to tell parent if child passed or failed. */
41 static int flag;
42
43 struct group users, sys, root, bin;
44 struct passwd nobody;
45 /*
46 * The following structure contains all test data. Each structure in the array
47 * is used for a separate test. The tests are executed in the for loop below.
48 */
49
50 struct test_data_t {
51 gid_t *real_gid;
52 gid_t *eff_gid;
53 int *exp_ret;
54 struct group *exp_real_usr;
55 struct group *exp_eff_usr;
56 char *test_msg;
57 } test_data[] = {
58 {
59 &sys.gr_gid, &bin.gr_gid, &pass, &sys, &bin,
60 "After setregid(sys, bin),"}, {
61 &neg_one, &sys.gr_gid, &pass, &sys, &sys, "After setregid(-1, sys)"},
62 {
63 &neg_one, &bin.gr_gid, &pass, &sys, &bin, "After setregid(-1, bin),"},
64 {
65 &bin.gr_gid, &neg_one, &pass, &bin, &bin, "After setregid(bin, -1),"},
66 {
67 &neg_one, &neg_one, &pass, &bin, &bin, "After setregid(-1, -1),"}, {
68 &neg_one, &bin.gr_gid, &pass, &bin, &bin, "After setregid(-1, bin),"},
69 {
70 &bin.gr_gid, &neg_one, &pass, &bin, &bin, "After setregid(bin, -1),"},
71 {
72 &bin.gr_gid, &bin.gr_gid, &pass, &bin, &bin,
73 "After setregid(bin, bin),"}, {
74 &sys.gr_gid, &neg_one, &fail, &bin, &bin, "After setregid(sys, -1)"},
75 {
76 &neg_one, &sys.gr_gid, &fail, &bin, &bin, "After setregid(-1, sys)"},
77 {
78 &sys.gr_gid, &sys.gr_gid, &fail, &bin, &bin,
79 "After setregid(sys, sys)"},};
80
81 int TST_TOTAL = sizeof(test_data) / sizeof(test_data[0]);
82
83 static void setup(void);
84 static void gid_verify(struct group *ru, struct group *eu, char *when);
85
main(int ac,char ** av)86 int main(int ac, char **av)
87 {
88 int lc;
89
90 tst_parse_opts(ac, av, NULL, NULL);
91
92 setup();
93
94 for (lc = 0; TEST_LOOPING(lc); lc++) {
95 pid_t pid;
96 int status, i;
97
98 pass = 0;
99 flag = 0;
100
101 tst_count = 0;
102
103 /* set the appropriate ownership values */
104 if (SETREGID(NULL, sys.gr_gid, bin.gr_gid) == -1)
105 tst_brkm(TBROK, NULL, "Initial setregid failed");
106
107 if (seteuid(nobody.pw_uid) == -1)
108 tst_brkm(TBROK, NULL, "Initial seteuid failed");
109
110 if ((pid = FORK_OR_VFORK()) == -1) {
111 tst_brkm(TBROK, NULL, "fork failed");
112 } else if (pid == 0) { /* child */
113 for (i = 0; i < TST_TOTAL; i++) {
114 gid_t test_ret;
115 /* Set the real or effective group id */
116 TEST(SETREGID(NULL, *test_data[i].real_gid,
117 *test_data[i].eff_gid));
118 test_ret = TEST_RETURN;
119
120 if (test_ret == *test_data[i].exp_ret) {
121 if (test_ret == neg_one) {
122 if (TEST_ERRNO != EPERM) {
123 tst_resm(TFAIL,
124 "setregid(%d, %d) "
125 "did not set errno "
126 "value as expected.",
127 *test_data
128 [i].real_gid,
129 *test_data
130 [i].eff_gid);
131 fail = -1;
132 continue;
133 } else {
134 tst_resm(TPASS,
135 "setregid(%d, %d) "
136 "failed as expected.",
137 *test_data
138 [i].real_gid,
139 *test_data
140 [i].eff_gid);
141 }
142 } else {
143 tst_resm(TPASS,
144 "setregid(%d, %d) "
145 "succeeded as expected.",
146 *test_data[i].real_gid,
147 *test_data[i].eff_gid);
148 }
149 } else {
150 tst_resm(TFAIL, "setregid(%d, %d) "
151 "did not return as expected.",
152 *test_data[i].real_gid,
153 *test_data[i].eff_gid);
154 flag = -1;
155 }
156 if (test_ret == -1) {
157 }
158
159 gid_verify(test_data[i].exp_real_usr,
160 test_data[i].exp_eff_usr,
161 test_data[i].test_msg);
162 }
163 exit(flag);
164 } else { /* parent */
165 waitpid(pid, &status, 0);
166 if (WEXITSTATUS(status) != 0) {
167 tst_resm(TFAIL, "test failed within "
168 "child process.");
169 }
170 }
171 }
172
173 tst_exit();
174 }
175
setup(void)176 static void setup(void)
177 {
178 struct group *junk;
179
180 tst_require_root();
181
182 tst_sig(FORK, DEF_HANDLER, NULL);
183
184 if (getpwnam("nobody") == NULL)
185 tst_brkm(TBROK, NULL, "nobody must be a valid user.");
186 nobody = *(getpwnam("nobody"));
187
188 #define GET_GID(group) do { \
189 junk = getgrnam(#group); \
190 if (junk == NULL) { \
191 tst_brkm(TBROK, NULL, "%s must be a valid group", #group); \
192 } \
193 GID16_CHECK(junk->gr_gid, setregid, NULL); \
194 group = *(junk); \
195 } while (0)
196
197 GET_GID(users);
198 GET_GID(sys);
199 GET_GID(bin);
200
201 TEST_PAUSE;
202 }
203
gid_verify(struct group * rg,struct group * eg,char * when)204 static void gid_verify(struct group *rg, struct group *eg, char *when)
205 {
206 if ((getgid() != rg->gr_gid) || (getegid() != eg->gr_gid)) {
207 tst_resm(TFAIL, "ERROR: %s real gid = %d; effective gid = %d",
208 when, getgid(), getegid());
209 tst_resm(TINFO, "Expected: real gid = %d; effective gid = %d",
210 rg->gr_gid, eg->gr_gid);
211 flag = -1;
212 } else {
213 tst_resm(TPASS, "real or effective gid was modified as expected");
214 }
215 }
216