1/******************************************************************************
2 * Copyright (c) Kerlabs 2008.                                                *
3 * Copyright (c) International Business Machines  Corp., 2008                 *
4 *  Created by Renaud Lottiaux                                                *
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 Foundation,   *
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA           *
19 *****************************************************************************/
20
21/*
22 * Check if setuid behaves correctly with file permissions. The test creates a
23 * file as ROOT with permissions 0644, does a setuid and then tries to open the
24 * file with RDWR permissions. The same test is done in a fork to check if new
25 * UIDs are correctly passed to the son.
26 */
27
28#include <errno.h>
29#include <pwd.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/wait.h>
33#include <fcntl.h>
34#include <unistd.h>
35
36#include "test.h"
37#include "compat_16.h"
38
39char *TCID = "setuid04";
40int TST_TOTAL = 1;
41
42static char nobody_uid[] = "nobody";
43static char testfile[] = "setuid04_testfile";
44static struct passwd *ltpuser;
45
46static int fd = -1;
47
48static void setup(void);
49static void cleanup(void);
50static void do_master_child(void);
51
52int main(int ac, char **av)
53{
54	pid_t pid;
55	int status;
56
57	tst_parse_opts(ac, av, NULL, NULL);
58
59	setup();
60
61	pid = FORK_OR_VFORK();
62	if (pid < 0)
63		tst_brkm(TBROK, cleanup, "Fork failed");
64
65	if (pid == 0) {
66		do_master_child();
67	} else {
68		waitpid(pid, &status, 0);
69		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
70			tst_resm(WEXITSTATUS(status),
71				 "son process exits with error");
72	}
73
74	cleanup();
75	tst_exit();
76}
77
78static void do_master_child(void)
79{
80	int lc;
81	int pid;
82	int status;
83
84	if (SETUID(NULL, ltpuser->pw_uid) == -1) {
85		tst_brkm(TBROK, NULL,
86			 "setuid failed to set the effective uid to %d",
87			 ltpuser->pw_uid);
88	}
89
90	for (lc = 0; TEST_LOOPING(lc); lc++) {
91		int tst_fd;
92
93		tst_count = 0;
94
95		TEST(tst_fd = open(testfile, O_RDWR));
96
97		if (TEST_RETURN != -1) {
98			tst_resm(TFAIL, "call succeeded unexpectedly");
99			close(tst_fd);
100		}
101
102		if (TEST_ERRNO == EACCES) {
103			tst_resm(TPASS, "open returned errno EACCES");
104		} else {
105			tst_resm(TFAIL, "open returned unexpected errno - %d",
106				 TEST_ERRNO);
107			continue;
108		}
109
110		pid = FORK_OR_VFORK();
111		if (pid < 0)
112			tst_brkm(TBROK, NULL, "Fork failed");
113
114		if (pid == 0) {
115			int tst_fd2;
116
117			/* Test to open the file in son process */
118			TEST(tst_fd2 = open(testfile, O_RDWR));
119
120			if (TEST_RETURN != -1) {
121				tst_resm(TFAIL, "call succeeded unexpectedly");
122				close(tst_fd2);
123			}
124
125			if (TEST_ERRNO == EACCES) {
126				tst_resm(TPASS, "open returned errno EACCES");
127			} else {
128				tst_resm(TFAIL,
129					 "open returned unexpected errno - %d",
130					 TEST_ERRNO);
131			}
132			tst_exit();
133		} else {
134			/* Wait for son completion */
135			waitpid(pid, &status, 0);
136			if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
137				exit(WEXITSTATUS(status));
138		}
139	}
140	tst_exit();
141}
142
143static void setup(void)
144{
145	tst_require_root();
146
147	ltpuser = getpwnam(nobody_uid);
148
149	if (ltpuser == NULL)
150		tst_brkm(TBROK, cleanup, "getpwnam failed for user id %s",
151			nobody_uid);
152
153	UID16_CHECK(ltpuser->pw_uid, setuid, cleanup);
154
155	tst_tmpdir();
156
157	/* Create test file */
158	fd = open(testfile, O_CREAT | O_RDWR, 0644);
159	if (fd < 0)
160		tst_brkm(TBROK, cleanup, "cannot creat test file");
161
162	tst_sig(FORK, DEF_HANDLER, cleanup);
163
164	TEST_PAUSE;
165}
166
167static void cleanup(void)
168{
169	close(fd);
170	tst_rmdir();
171}
172