fchmod02.c revision 0b9589f3f9c0345b29cfcf7da5a1253c708303eb
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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";
97int TST_TOTAL = 1;
98
99void setup();			/* Main setup function for the test */
100void cleanup();			/* Main cleanup function for the test */
101
102int main(int ac, char **av)
103{
104	struct stat stat_buf;	/* stat(2) struct contents */
105	int lc;
106	const char *msg;
107
108	msg = parse_opts(ac, av, NULL, NULL);
109	if (msg != NULL) {
110		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
111
112	}
113
114	setup();
115
116	for (lc = 0; TEST_LOOPING(lc); lc++) {
117
118		tst_count = 0;
119
120		/*
121		 * Call fchmod(2) with specified mode argument
122		 * (sticky-bit set) on testfile.
123		 */
124		TEST(fchmod(fd, PERMS));
125
126		if (TEST_RETURN == -1) {
127			tst_resm(TFAIL, "fchmod(%d, %#o) Failed, errno=%d : %s",
128				 fd, PERMS, TEST_ERRNO, strerror(TEST_ERRNO));
129			continue;
130		}
131		/*
132		 * Perform functional verification if test
133		 * executed without (-f) option.
134		 */
135		if (STD_FUNCTIONAL_TEST) {
136			/*
137			 * Get the testfile information using
138			 * fstat(2).
139			 */
140			if (fstat(fd, &stat_buf) < 0) {
141				tst_brkm(TFAIL, cleanup, "fstat(2) of %s "
142					 "failed, errno:%d", TESTFILE,
143					 TEST_ERRNO);
144			}
145
146			/* Check for expected mode permissions */
147			if ((stat_buf.st_mode & PERMS) == PERMS) {
148				tst_resm(TPASS, "Functionality of fchmod(%d, "
149					 "%#o) Successful", fd, PERMS);
150			} else {
151				tst_resm(TFAIL, "%s: Incorrect modes 0%03o, "
152					 "Expected 0%03o", TESTFILE,
153					 stat_buf.st_mode, PERMS);
154			}
155		} else {
156			tst_resm(TPASS, "call succeeded");
157		}
158	}
159
160	cleanup();
161
162	tst_exit();
163}
164
165/*
166 * void
167 * setup() - performs all ONE TIME setup for this test.
168 *  Create a temporary directory and change directory to it.
169 *  Create a test file under temporary directory.
170 *  Change the ownership of test file to that of "ltpuser1" user.
171 */
172void setup(void)
173{
174	struct passwd *ltpuser;	/* password struct for ltpuser1 */
175	struct group *ltpgroup;	/* group struct for ltpuser1 */
176	gid_t group1_gid;	/* user and process group id's */
177	uid_t user1_uid;
178
179	tst_sig(FORK, DEF_HANDLER, cleanup);
180
181	TEST_PAUSE;
182
183	/* Check that the test process id is super/root  */
184	if (geteuid() != 0) {
185		tst_brkm(TBROK, NULL, "Must be super/root for this test!");
186		tst_exit();
187	}
188
189	tst_tmpdir();
190
191	/* Get the uid of guest user - ltpuser1 */
192	if ((ltpuser = getpwnam(LTPUSER)) == NULL) {
193		tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER);
194	}
195	user1_uid = ltpuser->pw_uid;
196
197	/* Get the group id of guest user - ltpuser1 */
198	if ((ltpgroup = getgrnam(LTPGRP)) == NULL) {
199		tst_brkm(TBROK, cleanup, "%s not in /etc/group", LTPGRP);
200	}
201	group1_gid = ltpgroup->gr_gid;
202
203	/*
204	 * Create a test file under temporary directory with specified
205	 * mode permissios and set the ownership of the test file to the
206	 * uid/gid of guest user user1.
207	 */
208	if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) {
209		tst_brkm(TBROK, cleanup,
210			 "open(%s, O_RDWR|O_CREAT, %#o) Failed, errno=%d : %s",
211			 TESTFILE, FILE_MODE, errno, strerror(errno));
212	}
213
214	if (chown(TESTFILE, user1_uid, group1_gid) < 0) {
215		tst_brkm(TBROK, cleanup, "chown(2) of %s failed", TESTFILE);
216	}
217
218	/* Set the effective gid of the process to that of user */
219	if (setgid(group1_gid) < 0) {
220		tst_brkm(TBROK, cleanup, "setgid(2) to %d failed", group1_gid);
221	}
222}
223
224/*
225 * void
226 * cleanup() - performs all ONE TIME cleanup for this test at
227 *	       completion or premature exit.
228 *  Close the testfile created in the setup.
229 *  Remove the test directory and testfile created in the setup.
230 */
231void cleanup(void)
232{
233	/*
234	 * print timing stats if that option was specified.
235	 */
236	TEST_CLEANUP;
237
238	/* Close the testfile created in the setup() */
239	if (close(fd) == -1) {
240		tst_brkm(TBROK, NULL, "close(%s) Failed, errno=%d : %s",
241			 TESTFILE, errno, strerror(errno));
242	}
243
244	tst_rmdir();
245
246}
247