1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci *   Copyright (c) International Business Machines  Corp., 2000
3f08c3bdfSopenharmony_ci *   Copyright (c) 2010 Cyril Hrubis chrubis@suse.cz
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci *   This program is free software;  you can redistribute it and/or modify
6f08c3bdfSopenharmony_ci *   it under the terms of the GNU General Public License as published by
7f08c3bdfSopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
8f08c3bdfSopenharmony_ci *   (at your option) any later version.
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci *   This program is distributed in the hope that it will be useful,
11f08c3bdfSopenharmony_ci *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12f08c3bdfSopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13f08c3bdfSopenharmony_ci *   the GNU General Public License for more details.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *   You should have received a copy of the GNU General Public License
16f08c3bdfSopenharmony_ci *   along with this program;  if not, write to the Free Software
17f08c3bdfSopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci/*
21f08c3bdfSopenharmony_ci *  FILE(s)     : fs_perms.c simpletest.sh textx.o Makefile README
22f08c3bdfSopenharmony_ci *  DESCRIPTION : Regression test for Linux filesystem permissions.
23f08c3bdfSopenharmony_ci *  AUTHOR      : Jeff Martin (martinjn@us.ibm.com)
24f08c3bdfSopenharmony_ci *  HISTORY     :
25f08c3bdfSopenharmony_ci *     (04/12/01)v.99  First attempt at using C for fs-regression test.  Only tests read and write bits.
26f08c3bdfSopenharmony_ci *     (04/19/01)v1.0  Added test for execute bit.
27f08c3bdfSopenharmony_ci *     (05/23/01)v1.1  Added command line parameter to specify test file.
28f08c3bdfSopenharmony_ci *     (07/12/01)v1.2  Removed conf file and went to command line parameters.
29f08c3bdfSopenharmony_ci *     (10/19/04)      Rewritten to fit ltp test interface.
30f08c3bdfSopenharmony_ci *                     Also now we try to run two different files, one is executed by execl,
31f08c3bdfSopenharmony_ci *                     has shebang and should end up executed by kernel, other one is empty
32f08c3bdfSopenharmony_ci *                     is executed by execlp and should end up executed by libc.
33f08c3bdfSopenharmony_ci */
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci#include <stdio.h>
36f08c3bdfSopenharmony_ci#include <string.h>
37f08c3bdfSopenharmony_ci#include <ctype.h>
38f08c3bdfSopenharmony_ci#include <sys/stat.h>
39f08c3bdfSopenharmony_ci#include <sys/types.h>
40f08c3bdfSopenharmony_ci#include <stdlib.h>
41f08c3bdfSopenharmony_ci#include <unistd.h>
42f08c3bdfSopenharmony_ci#include <sys/wait.h>
43f08c3bdfSopenharmony_ci#include <linux/limits.h>
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci#include "test.h"
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci#define TEST_FILE_NAME1 "./test.file1"
48f08c3bdfSopenharmony_ci#define TEST_FILE_NAME2 "./test.file2"
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_cichar *TCID = "fs_perms";
51f08c3bdfSopenharmony_ciint TST_TOTAL = 1;
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_cistatic void cleanup(void)
54f08c3bdfSopenharmony_ci{
55f08c3bdfSopenharmony_ci	seteuid(0);
56f08c3bdfSopenharmony_ci	setegid(0);
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci	tst_rmdir();
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci}
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci/*
63f08c3bdfSopenharmony_ci * Create file and set permissions, user id, group id.
64f08c3bdfSopenharmony_ci *
65f08c3bdfSopenharmony_ci * If flag is non zero, the file contains #!/PATH/sh shebang otherwise it's
66f08c3bdfSopenharmony_ci * empty.
67f08c3bdfSopenharmony_ci */
68f08c3bdfSopenharmony_cistatic void testsetup(const char *file_name, int flag, mode_t mode,
69f08c3bdfSopenharmony_ci		      int user_id, int group_id)
70f08c3bdfSopenharmony_ci{
71f08c3bdfSopenharmony_ci	FILE *file;
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	file = fopen(file_name, "w");
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci	if (file == NULL)
76f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup,
77f08c3bdfSopenharmony_ci			 "Could not create test file %s.", file_name);
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	/* create file with shebang */
80f08c3bdfSopenharmony_ci	if (flag) {
81f08c3bdfSopenharmony_ci		char buf[PATH_MAX];
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci		if (tst_get_path("sh", buf, PATH_MAX))
84f08c3bdfSopenharmony_ci			tst_brkm(TBROK, cleanup,
85f08c3bdfSopenharmony_ci				 "Could not find path to sh in $PATH.");
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci		if (fprintf(file, "#!%s\n", buf) < 0)
88f08c3bdfSopenharmony_ci			tst_brkm(TBROK, cleanup, "Calling fprintf failed.");
89f08c3bdfSopenharmony_ci	}
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	if (fclose(file))
92f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "Calling fclose failed.");
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci	if (chmod(file_name, mode))
95f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup,
96f08c3bdfSopenharmony_ci			 "Could not chmod test file %s.", file_name);
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	if (chown(file_name, user_id, group_id))
99f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup,
100f08c3bdfSopenharmony_ci			 "Could not chown test file %s.", file_name);
101f08c3bdfSopenharmony_ci}
102f08c3bdfSopenharmony_ci
103f08c3bdfSopenharmony_ci/*
104f08c3bdfSopenharmony_ci * Test permissions.
105f08c3bdfSopenharmony_ci */
106f08c3bdfSopenharmony_cistatic int testfperm(const char *file_name, int flag, int user_id,
107f08c3bdfSopenharmony_ci		     int group_id, char *fperm)
108f08c3bdfSopenharmony_ci{
109f08c3bdfSopenharmony_ci	FILE *file;
110f08c3bdfSopenharmony_ci	int status;
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	switch (fork()) {
113f08c3bdfSopenharmony_ci	case 0:
114f08c3bdfSopenharmony_ci		if (setgid(group_id))
115f08c3bdfSopenharmony_ci			tst_brkm(TBROK | TERRNO, cleanup,
116f08c3bdfSopenharmony_ci				 "Could not setgid to %d.", group_id);
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_ci		if (setuid(user_id))
119f08c3bdfSopenharmony_ci			tst_brkm(TBROK | TERRNO, cleanup,
120f08c3bdfSopenharmony_ci				 "Could not setuid to %d.", user_id);
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci		switch (tolower(fperm[0])) {
123f08c3bdfSopenharmony_ci		case 'x':
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_ci			/*
126f08c3bdfSopenharmony_ci			 * execlp runs file with sh in case kernel has
127f08c3bdfSopenharmony_ci			 * no binmft handler for it, execl does not.
128f08c3bdfSopenharmony_ci			 */
129f08c3bdfSopenharmony_ci			if (flag)
130f08c3bdfSopenharmony_ci				execl(file_name, file_name, NULL);
131f08c3bdfSopenharmony_ci			else
132f08c3bdfSopenharmony_ci				execlp(file_name, "test", NULL);
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci			exit(1);
135f08c3bdfSopenharmony_ci			break;
136f08c3bdfSopenharmony_ci		default:
137f08c3bdfSopenharmony_ci			if ((file = fopen(file_name, fperm)) != NULL) {
138f08c3bdfSopenharmony_ci				fclose(file);
139f08c3bdfSopenharmony_ci				exit(0);
140f08c3bdfSopenharmony_ci			}
141f08c3bdfSopenharmony_ci			exit(1);
142f08c3bdfSopenharmony_ci			break;
143f08c3bdfSopenharmony_ci		}
144f08c3bdfSopenharmony_ci		break;
145f08c3bdfSopenharmony_ci	case -1:
146f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
147f08c3bdfSopenharmony_ci		break;
148f08c3bdfSopenharmony_ci	default:
149f08c3bdfSopenharmony_ci		break;
150f08c3bdfSopenharmony_ci	}
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci	wait(&status);
153f08c3bdfSopenharmony_ci
154f08c3bdfSopenharmony_ci	return WEXITSTATUS(status);
155f08c3bdfSopenharmony_ci}
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_cistatic void print_usage(const char *bname)
158f08c3bdfSopenharmony_ci{
159f08c3bdfSopenharmony_ci	char *usage = "<file mode> <file UID> <file GID> "
160f08c3bdfSopenharmony_ci	    "<tester UID> <tester GID> <permission "
161f08c3bdfSopenharmony_ci	    "to test r|w|x> <expected result 0|1>";
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci	printf("Usage: %s %s\n", bname, usage);
164f08c3bdfSopenharmony_ci}
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_cistatic long str_to_l(const char *str, const char *name, int base)
167f08c3bdfSopenharmony_ci{
168f08c3bdfSopenharmony_ci	char *end;
169f08c3bdfSopenharmony_ci	long i = strtol(str, &end, base);
170f08c3bdfSopenharmony_ci
171f08c3bdfSopenharmony_ci	if (*end != '\0')
172f08c3bdfSopenharmony_ci		tst_brkm(TBROK, NULL, "Invalid parameter '%s' passed. (%s)",
173f08c3bdfSopenharmony_ci			 name, str);
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci	return i;
176f08c3bdfSopenharmony_ci}
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
179f08c3bdfSopenharmony_ci{
180f08c3bdfSopenharmony_ci	char *fperm;
181f08c3bdfSopenharmony_ci	gid_t fgroup_id, group_id;
182f08c3bdfSopenharmony_ci	uid_t fuser_id, user_id;
183f08c3bdfSopenharmony_ci	mode_t fmode;
184f08c3bdfSopenharmony_ci	int exp_res;
185f08c3bdfSopenharmony_ci	int res1, res2 = 1;
186f08c3bdfSopenharmony_ci
187f08c3bdfSopenharmony_ci	tst_require_root();
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci	if (argc != 8) {
190f08c3bdfSopenharmony_ci		print_usage(argv[0]);
191f08c3bdfSopenharmony_ci		tst_exit();
192f08c3bdfSopenharmony_ci	}
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	if (strlen(argv[6]) > 1) {
195f08c3bdfSopenharmony_ci		print_usage(argv[0]);
196f08c3bdfSopenharmony_ci		tst_exit();
197f08c3bdfSopenharmony_ci	}
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci	fmode = str_to_l(argv[1], "file mode", 8);
200f08c3bdfSopenharmony_ci	fuser_id = str_to_l(argv[2], "file uid", 10);
201f08c3bdfSopenharmony_ci	fgroup_id = str_to_l(argv[3], "file gid", 10);
202f08c3bdfSopenharmony_ci	user_id = str_to_l(argv[4], "tester uid", 10);
203f08c3bdfSopenharmony_ci	group_id = str_to_l(argv[5], "tester gid", 10);
204f08c3bdfSopenharmony_ci	fperm = argv[6];
205f08c3bdfSopenharmony_ci	exp_res = str_to_l(argv[7], "expected result", 10);
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ci	tst_tmpdir();
208f08c3bdfSopenharmony_ci	testsetup(TEST_FILE_NAME1, 0, fmode, fuser_id, fgroup_id);
209f08c3bdfSopenharmony_ci
210f08c3bdfSopenharmony_ci	/* more tests for 'x' flag */
211f08c3bdfSopenharmony_ci	if (tolower(fperm[0]) == 'x') {
212f08c3bdfSopenharmony_ci		testsetup(TEST_FILE_NAME2, 1, fmode, fuser_id, fgroup_id);
213f08c3bdfSopenharmony_ci		res2 = testfperm(TEST_FILE_NAME2, 1, user_id, group_id, fperm);
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_ci		if (res2 == exp_res)
216f08c3bdfSopenharmony_ci			res2 = 1;
217f08c3bdfSopenharmony_ci		else
218f08c3bdfSopenharmony_ci			res2 = 0;
219f08c3bdfSopenharmony_ci	}
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_ci	res1 = testfperm(TEST_FILE_NAME1, 0, user_id, group_id, fperm);
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_ci	tst_resm((exp_res == res1) && res2 ? TPASS : TFAIL,
224f08c3bdfSopenharmony_ci		 "%c a %03o file owned by (%d/%d) as user/group (%d/%d)",
225f08c3bdfSopenharmony_ci		 fperm[0], fmode, fuser_id, fgroup_id, user_id, group_id);
226f08c3bdfSopenharmony_ci	tst_rmdir();
227f08c3bdfSopenharmony_ci	tst_exit();
228f08c3bdfSopenharmony_ci}
229