chown02.c revision 53740500924f6439623a8ac256b5be2d6c59ed1f
1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2001
4 *
5 *   This program is free software;  you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 *   the GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program;  if not, write to the Free Software
17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name: chown02
22 *
23 * Test Description:
24 *  Verify that, when chown(2) invoked by super-user to change the owner and
25 *  group of a file specified by path to any numeric owner(uid)/group(gid)
26 *  values,
27 *	- clears setuid and setgid bits set on an executable file.
28 *	- preserves setgid bit set on a non-group-executable file.
29 *
30 * Expected Result:
31 *  chown(2) should return 0 and the ownership set on the file should match
32 *  the numeric values contained in owner and group respectively.
33 *
34 * Algorithm:
35 *  Setup:
36 *   Setup signal handling.
37 *   Create temporary directory.
38 *   Pause for SIGUSR1 if option specified.
39 *
40 *  Test:
41 *   Loop if the proper options are given.
42 *   Execute system call
43 *   Check return code, if system call failed (return=-1)
44 *   	Log the errno and Issue a FAIL message.
45 *   Otherwise,
46 *   	Verify the Functionality of system call
47 *      if successful,
48 *      	Issue Functionality-Pass message.
49 *      Otherwise,
50 *		Issue Functionality-Fail message.
51 *  Cleanup:
52 *   Print errno log and/or timing stats if options given
53 *   Delete the temporary directory created.
54 *
55 * Usage:  <for command-line>
56 *  chown02 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
57 *     where,  -c n : Run n copies concurrently.
58 *             -f   : Turn off functionality Testing.
59 *	       -i n : Execute test n times.
60 *	       -I x : Execute test for x seconds.
61 *	       -P x : Pause for x seconds between iterations.
62 *	       -t   : Turn on syscall timing.
63 *
64 * HISTORY
65 *	07/2001 Ported by Wayne Boyer
66 *
67 * RESTRICTIONS:
68 *  This test should be run by 'super-user' (root) only.
69 *
70 */
71
72#include <stdio.h>
73#include <sys/types.h>
74#include <sys/stat.h>
75#include <sys/fcntl.h>
76#include <errno.h>
77#include <string.h>
78#include <signal.h>
79
80#include "test.h"
81#include "usctest.h"
82
83#define FILE_MODE	S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
84#define NEW_PERMS1	S_IFREG | S_IRWXU | S_IRWXG | S_ISUID | S_ISGID
85#define NEW_PERMS2	S_IFREG | S_IRWXU | S_ISGID
86#define EXP_PERMS	S_IFREG | S_IRWXU | S_IRWXG
87#define TESTFILE1	"testfile1"
88#define TESTFILE2	"testfile2"
89
90char *TCID = "chown02";		/* Test program identifier.    */
91int TST_TOTAL = 1;		/* Total number of test conditions */
92extern int Tst_count;		/* Test Case counter for tst_* routines */
93
94int no_setup();
95int setup1();			/* Test specific setup functions */
96int setup2();
97
98struct test_case_t {
99	char *pathname;
100	char *desc;
101	uid_t user_id;
102	gid_t group_id;
103	int test_flag;
104	int (*setupfunc) ();
105} Test_cases[] = {
106	{
107	TESTFILE1, "Setuid/Setgid bits cleared", 700, 701, 1, setup1}, {
108	TESTFILE2, "Setgid bit not cleared", 700, 701, 2, setup2}, {
109NULL, NULL, 0, 0, 0, no_setup},};
110
111void setup();			/* setup function for the test */
112void cleanup();			/* cleanup function for the test */
113
114int main(int ac, char **av)
115{
116	struct stat stat_buf;	/* stat(2) struct contents */
117	int lc;			/* loop counter */
118	char *msg;		/* message returned from parse_opts */
119	int ind;		/* counter variable for chmod(2) tests */
120	uid_t user_id;		/* user id of the user set for testfile */
121	gid_t group_id;		/* group id of the user set for testfile */
122	int test_flag;		/* test condition specific flag variable */
123	char *file_name;	/* ptr. for test file name */
124	char *test_desc;	/* test specific message */
125
126	/* Parse standard options given to run the test. */
127<<<<<<< HEAD
128	msg = parse_opts(ac, av, NULL, NULL);
129=======
130	msg = parse_opts(ac, av, (option_t *) NULL, NULL);
131>>>>>>> master
132	if (msg != NULL) {
133		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
134		tst_exit();
135	}
136
137	/* Perform global setup for test */
138	setup();
139
140	/* Check looping state if -i option given */
141	for (lc = 0; TEST_LOOPING(lc); lc++) {
142		/* Reset Tst_count in case we are looping. */
143		Tst_count = 0;
144
145		for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
146
147			file_name = Test_cases[ind].pathname;
148			test_desc = Test_cases[ind].desc;
149			user_id = Test_cases[ind].user_id;
150			group_id = Test_cases[ind].group_id;
151			test_flag = Test_cases[ind].test_flag;
152
153			/*
154			 * Call chown(2) with different user id and
155			 * group id (numeric values) to set it on testfile.
156			 */
157			TEST(chown(file_name, user_id, group_id));
158
159			/* check return code of chown(2) */
160			if (TEST_RETURN == -1) {
161				tst_resm(TFAIL,
162					 "chown() Fails on %s, errno=%d",
163					 file_name, TEST_ERRNO);
164				continue;
165			}
166
167			/*
168			 * Perform functional verification if test
169			 * executed without (-f) option.
170			 */
171			if (STD_FUNCTIONAL_TEST) {
172				/*
173				 * Get the testfile information using stat(2).
174				 */
175				if (stat(file_name, &stat_buf) < 0) {
176					tst_brkm(TFAIL, cleanup, "stat(2) of "
177						 "%s failed, errno:%d",
178						 file_name, TEST_ERRNO);
179				}
180
181				/*
182				 * Check for expected Ownership ids
183				 * set on testfile.
184				 */
185				if ((stat_buf.st_uid != user_id) ||
186				    (stat_buf.st_gid != group_id)) {
187					tst_brkm(TFAIL, cleanup, "%s: Incorrect"
188						 " ownership set, Expected %d "
189						 "%d", file_name,
190						 user_id, group_id);
191				}
192
193				/*
194				 * Verify that S_ISUID/S_ISGID bits set on the
195				 * testfile(s) in setup()s are cleared by
196				 * chown().
197				 */
198				if ((test_flag == 1) &&
199				    ((stat_buf.st_mode &
200				      (S_ISUID | S_ISGID)))) {
201					tst_resm(TFAIL, "%s: Incorrect mode "
202						 "permissions %#o, Expected "
203						 "%#o", file_name, NEW_PERMS1,
204						 EXP_PERMS);
205				} else if ((test_flag == 2) &&
206					   (!(stat_buf.st_mode & S_ISGID))) {
207					tst_resm(TFAIL, "%s: Incorrect mode "
208						 "permissions %#o, Expected "
209						 "%#o", file_name,
210						 stat_buf.st_mode, NEW_PERMS2);
211				} else {
212					tst_resm(TPASS,
213						 "chown() on %s succeeds : %s",
214						 file_name, test_desc);
215				}
216			} else {
217				tst_resm(TPASS, "call succeeded");
218			}
219		}
220	}			/* End for TEST_LOOPING */
221
222	/* Call cleanup() to undo setup done for the test. */
223	cleanup();
224
225	return 0;
226 }		/* End main */
227
228/*
229 * void
230 * setup() - performs all ONE TIME setup for this test.
231 *  Create a temporary directory and change directory to it.
232 *  Create a test file under temporary directory and close it
233 */
234void setup()
235{
236	int ind;
237
238	/* capture signals */
239	tst_sig(NOFORK, DEF_HANDLER, cleanup);
240
241	/* Check that the test process id is super/root  */
242	if (geteuid() != 0) {
243		tst_brkm(TBROK, NULL, "Must be super/root for this test!");
244		tst_exit();
245	}
246
247	/* Pause if that option was specified */
248	TEST_PAUSE;
249
250	/* make a temp directory and cd to it */
251	tst_tmpdir();
252
253	/* call individual setup functions */
254	for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
255		Test_cases[ind].setupfunc();
256	}
257}				/* End setup() */
258
259/*
260 * int
261 * setup1() - Setup function for chown(2) to verify setuid/setgid bits
262 *	      set on an executable file will not be cleared.
263 *  Creat a testfile and set setuid/setgid bits on the mode of file.$
264 */
265int setup1()
266{
267	int fd;			/* File descriptor for testfile1 */
268
269	/* Creat a testfile and close it */
270	if ((fd = open(TESTFILE1, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
271		tst_brkm(TBROK|TERRNO, cleanup,
272			 "open(%s, O_RDWR|O_CREAT, %o) failed",
273			 TESTFILE1, FILE_MODE);
274	}
275	if (close(fd) == -1) {
276		tst_brkm(TBROK|TERRNO, cleanup,
277			 "close(%s) failed",
278			 TESTFILE1);
279	}
280
281	/* Set setuid/setgid bits on the test file created */
282	if (chmod(TESTFILE1, NEW_PERMS1) != 0) {
283		tst_brkm(TBROK|TERRNO, cleanup,
284			 "chmod(%s) failed",
285			 TESTFILE1);
286	}
287	return 0;
288}				/* End setup1() */
289
290/*
291 * int
292 * setup2() - Setup function for chown(2) to verify setgid bit set
293 *	      set on non-group executable file will not be cleared.
294 *  Creat a testfile and set setgid bit on the mode of file.
295 */
296int setup2()
297{
298	int fd;			/* File descriptor for testfile2 */
299
300	/* Creat a testfile and close it */
301	if ((fd = open(TESTFILE2, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
302		tst_brkm(TBROK|TERRNO, cleanup,
303			 "open(%s, O_RDWR|O_CREAT, %o) failed",
304			 TESTFILE2, FILE_MODE);
305	}
306	if (close(fd) == -1) {
307		tst_brkm(TBROK|TERRNO, cleanup,
308			 "close(%s) failed",
309			 TESTFILE2);
310	}
311
312	/* Set setgid bit on the test file created */
313	if (chmod(TESTFILE2, NEW_PERMS2) != 0) {
314		tst_brkm(TBROK|TERRNO, cleanup,
315			 "chmod(%s) failed",
316			 TESTFILE2);
317	}
318	return 0;
319}
320
321/*
322 * int
323 * no_setup() - Some test conditions for mknod(2) do not any setup.
324 * 		Hence, this function just returns 0.
325 *  This function simply returns 0.
326 */
327int no_setup()
328{
329	return 0;
330}
331
332/*
333 * void
334 * cleanup() - performs all ONE TIME cleanup for this test at
335 *	       completion or premature exit.
336 *  Remove the test directory and testfile created in the setup.
337 */
338void cleanup()
339{
340	/*
341	 * print timing stats if that option was specified.
342	 */
343	TEST_CLEANUP;
344
345	/* Remove tmp dir and all files in it */
346	tst_rmdir();
347
348	/* exit with return code appropriate for results */
349	tst_exit();
350}				/* End cleanup() */
351