fchmod02.c revision 2c28215423293e443469a07ae7011135d058b671
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: fchmod02
22 *
23 * Test Description:
24 *  Verify that, fchmod(2) will succeed to change the mode of a file/directory
25 *  set the sticky bit on it if invoked by root (uid = 0) process with
26 *  the following constraints,
27 *	- the process is not the owner of the file/directory.
28 *	- the effective group ID or one of the supplementary group ID's of the
29 *	  process is equal to the group ID of the file/directory.
30 *
31 * Expected Result:
32 *  fchmod() should return value 0 on success and succeeds to set sticky bit
33 *  on the specified file.
34 *
35 * Algorithm:
36 *  Setup:
37 *   Setup signal handling.
38 *   Create temporary directory.
39 *   Pause for SIGUSR1 if option specified.
40 *
41 *  Test:
42 *   Loop if the proper options are given.
43 *   Execute system call
44 *   Check return code, if system call failed (return=-1)
45 *   	Log the errno and Issue a FAIL message.
46 *   Otherwise,
47 *   	Verify the Functionality of system call
48 *      if successful,
49 *      	Issue Functionality-Pass message.
50 *      Otherwise,
51 *		Issue Functionality-Fail message.
52 *  Cleanup:
53 *   Print errno log and/or timing stats if options given
54 *   Delete the temporary directory created.
55 *
56 * Usage:  <for command-line>
57 *  fchmod02 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
58 *     where,  -c n : Run n copies concurrently.
59 *             -f   : Turn off functionality Testing.
60 *	       -i n : Execute test n times.
61 *	       -I x : Execute test for x seconds.
62 *	       -P x : Pause for x seconds between iterations.
63 *	       -t   : Turn on syscall timing.
64 *
65 * HISTORY
66 *	07/2001 Ported by Wayne Boyer
67 *
68 * RESTRICTIONS:
69 *  This test should be run by 'super-user' (root) only.
70 *
71 */
72
73#include <stdio.h>
74#include <sys/types.h>
75#include <sys/stat.h>
76#include <sys/fcntl.h>
77#include <errno.h>
78#include <string.h>
79#include <signal.h>
80#include <grp.h>
81#include <pwd.h>
82
83#include "test.h"
84#include "usctest.h"
85
86#define LTPUSER		"nobody"
87#define LTPGRP		"users"
88#define FILE_MODE 	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
89#define PERMS		01777	/*
90				 * Mode permissions of test file with sticky
91				 * bit set.
92				 */
93#define TESTFILE	"testfile"
94
95int fd;				/* file descriptor variable */
96char *TCID = "fchmod02";	/* Test program identifier.    */
97int TST_TOTAL = 1;		/* Total number of test cases. */
98extern int Tst_count;		/* Test Case counter for tst_* routines */
99
100void setup();			/* Main setup function for the test */
101void cleanup();			/* Main cleanup function for the test */
102
103int main(int ac, char **av)
104{
105	struct stat stat_buf;	/* stat(2) struct contents */
106	int lc;			/* loop counter */
107	char *msg;		/* message returned from parse_opts */
108
109	/* Parse standard options given to run the test. */
110<<<<<<< HEAD
111	msg = parse_opts(ac, av, NULL, NULL);
112=======
113	msg = parse_opts(ac, av, (option_t *) NULL, NULL);
114>>>>>>> master
115	if (msg != NULL) {
116		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
117
118	}
119
120	setup();
121
122	for (lc = 0; TEST_LOOPING(lc); lc++) {
123
124		Tst_count = 0;
125
126		/*
127		 * Call fchmod(2) with specified mode argument
128		 * (sticky-bit set) on testfile.
129		 */
130		TEST(fchmod(fd, PERMS));
131
132		if (TEST_RETURN == -1) {
133			tst_resm(TFAIL, "fchmod(%d, %#o) Failed, errno=%d : %s",
134				 fd, PERMS, TEST_ERRNO, strerror(TEST_ERRNO));
135			continue;
136		}
137		/*
138		 * Perform functional verification if test
139		 * executed without (-f) option.
140		 */
141		if (STD_FUNCTIONAL_TEST) {
142			/*
143			 * Get the testfile information using
144			 * fstat(2).
145			 */
146			if (fstat(fd, &stat_buf) < 0) {
147				tst_brkm(TFAIL, cleanup, "fstat(2) of %s "
148					 "failed, errno:%d", TESTFILE,
149					 TEST_ERRNO);
150			}
151
152			/* Check for expected mode permissions */
153			if ((stat_buf.st_mode & PERMS) == PERMS) {
154				tst_resm(TPASS, "Functionality of fchmod(%d, "
155					 "%#o) Successful", fd, PERMS);
156			} else {
157				tst_resm(TFAIL, "%s: Incorrect modes 0%03o, "
158					 "Expected 0%03o", TESTFILE,
159					 stat_buf.st_mode, PERMS);
160			}
161		} else {
162			tst_resm(TPASS, "call succeeded");
163		}
164	}
165
166	cleanup();
167
168	  return 0;
169}
170
171/*
172 * void
173 * setup() - performs all ONE TIME setup for this test.
174 *  Create a temporary directory and change directory to it.
175 *  Create a test file under temporary directory.
176 *  Change the ownership of test file to that of "ltpuser1" user.
177 */
178void setup()
179{
180	struct passwd *ltpuser;	/* password struct for ltpuser1 */
181	struct group *ltpgroup;	/* group struct for ltpuser1 */
182	gid_t group1_gid;	/* user and process group id's */
183	uid_t user1_uid;
184
185	tst_sig(FORK, DEF_HANDLER, cleanup);
186
187	TEST_PAUSE;
188
189	/* Check that the test process id is super/root  */
190	if (geteuid() != 0) {
191		tst_brkm(TBROK, NULL, "Must be super/root for this test!");
192		tst_exit();
193	}
194
195	tst_tmpdir();
196
197	/* Get the uid of guest user - ltpuser1 */
198	if ((ltpuser = getpwnam(LTPUSER)) == NULL) {
199		tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER);
200	}
201	user1_uid = ltpuser->pw_uid;
202
203	/* Get the group id of guest user - ltpuser1 */
204	if ((ltpgroup = getgrnam(LTPGRP)) == NULL) {
205		tst_brkm(TBROK, cleanup, "%s not in /etc/group", LTPGRP);
206	}
207	group1_gid = ltpgroup->gr_gid;
208
209	/*
210	 * Create a test file under temporary directory with specified
211	 * mode permissios and set the ownership of the test file to the
212	 * uid/gid of guest user user1.
213	 */
214	if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
215		tst_brkm(TBROK, cleanup,
216			 "open(%s, O_RDWR|O_CREAT, %#o) Failed, errno=%d : %s",
217			 TESTFILE, FILE_MODE, errno, strerror(errno));
218	}
219
220	if (chown(TESTFILE, user1_uid, group1_gid) < 0) {
221		tst_brkm(TBROK, cleanup, "chown(2) of %s failed", TESTFILE);
222	}
223
224	/* Set the effective gid of the process to that of user */
225	if (setgid(group1_gid) < 0) {
226		tst_brkm(TBROK, cleanup, "setgid(2) to %d failed", group1_gid);
227	}
228}
229
230/*
231 * void
232 * cleanup() - performs all ONE TIME cleanup for this test at
233 *	       completion or premature exit.
234 *  Close the testfile created in the setup.
235 *  Remove the test directory and testfile created in the setup.
236 */
237void cleanup()
238{
239	/*
240	 * print timing stats if that option was specified.
241	 */
242	TEST_CLEANUP;
243
244	/* Close the testfile created in the setup() */
245	if (close(fd) == -1) {
246		tst_brkm(TBROK, NULL, "close(%s) Failed, errno=%d : %s",
247			 TESTFILE, errno, strerror(errno));
248	}
249
250	tst_rmdir();
251
252}