3 * Copyright (c) International Business Machines Corp., 2001
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.
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.
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
24 * Verify that, fchmod(2) will succeed to change the mode of a directory
25 * but fails to set the setgid bit on it if invoked by non-root (uid != 0)
26 * process with the following constraints,
27 * - the process is the owner of the directory.
28 * - the effective group ID or one of the supplementary group ID's of the
29 * process is not equal to the group ID of the directory.
32 * fchmod() should return value 0 on success and though succeeds to change
33 * the mode of a directory but fails to set setgid bit on it.
37 * Setup signal handling.
38 * Create temporary directory.
39 * Pause for SIGUSR1 if option specified.
42 * Loop if the proper options are given.
44 * Check return code, if system call failed (return=-1)
45 * Log the errno and Issue a FAIL message.
47 * Verify the Functionality of system call
49 * Issue Functionality-Pass message.
51 * Issue Functionality-Fail message.
53 * Print errno log and/or timing stats if options given
54 * Delete the temporary directory created.
56 * Usage: <for command-line>
57 * fchmod05 [-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.
66 * 07/2001 Ported by Wayne Boyer
69 * This test should be run by 'non-super-user' only.
79 #include <sys/types.h>
81 #include <sys/fcntl.h>
92 #define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
94 #define TESTDIR "testdir"
96 int fd
; /* file descriptor for test directory */
97 char *TCID
="fchmod05"; /* Test program identifier. */
98 int TST_TOTAL
=1; /* Total number of test cases. */
99 extern int Tst_count
; /* Test Case counter for tst_* routines */
101 void setup(); /* Main setup function for test */
102 void cleanup(); /* Main cleanup function for test */
105 main(int ac
, char **av
)
107 struct stat stat_buf
; /* stat struct */
108 int lc
; /* loop counter */
109 char *msg
; /* message returned from parse_opts */
110 mode_t dir_mode
; /* mode permissions set on test directory */
112 /* Parse standard options given to run the test. */
113 msg
= parse_opts(ac
, av
, (option_t
*) NULL
, NULL
);
114 if (msg
!= (char *) NULL
) {
115 tst_brkm(TBROK
, NULL
, "OPTION PARSING ERROR - %s", msg
);
119 /* Perform global setup for test */
122 /* Check looping state if -i option given */
123 for (lc
= 0; TEST_LOOPING(lc
); lc
++) {
124 /* Reset Tst_count in case we are looping. */
128 * Call fchmod(2) with mode argument
129 * to set setgid bit on TESTDIR.
132 TEST(fchmod(fd
, PERMS
));
134 /* check return code of fchmod(2) */
135 if (TEST_RETURN
== -1) {
136 tst_resm(TFAIL
, "fchmod(%d, %#o) Failed, errno=%d : %s",
137 fd
, PERMS
, TEST_ERRNO
, strerror(TEST_ERRNO
));
141 * Perform functional verification if test
142 * executed without (-f) option.
144 if (STD_FUNCTIONAL_TEST
) {
146 * Get the directory information using
149 if (fstat(fd
, &stat_buf
) < 0) {
150 tst_brkm(TFAIL
, cleanup
,
151 "fstat(2) of %s failed, errno:%d",
152 TESTDIR
, TEST_ERRNO
);
154 dir_mode
= stat_buf
.st_mode
;
155 if (PERMS
!= dir_mode
) {
156 tst_resm(TFAIL
, "%s: Incorrect modes 0%03o, "
158 TESTDIR
, PERMS
, MODE_RWX
);
160 tst_resm(TPASS
, "Functionality of fchmod(%d, "
161 "%#o) successful", fd
, PERMS
);
164 tst_resm(TPASS
, "call succeeded");
166 } /* End for TEST_LOOPING */
168 /* Call cleanup() to undo setup done for the test. */
177 * setup() - performs all ONE TIME setup for this test.
178 * Create a temporary directory and cd to it.
179 * Create a test directory under temporary directory.
180 * Invoke setuid to root program to modify group ownership
182 * Open the test directory for reading.
187 char *test_home
; /* variable to hold TESTHOME env */
188 struct passwd
* nobody_u
;
189 struct group
* bin_group
;
191 /* capture signals */
192 tst_sig(FORK
, DEF_HANDLER
, cleanup
);
194 /* Check that the test process id is not super/root */
195 if (geteuid() != 0) {
196 tst_brkm(TBROK
, NULL
, "Must be super/root for this test!");
200 test_home
= get_current_dir_name();
202 /* Pause if that option was specified */
205 /* make a temp directory and cd to it */
208 nobody_u
=getpwnam("nobody");
210 tst_brkm(TBROK
, cleanup
,
211 "Couldn't find uid of nobody: %s", strerror(errno
));
213 bin_group
=getgrnam("bin");
215 tst_brkm(TBROK
, cleanup
,
216 "Couldn't find gid of bin: %s", strerror(errno
));
218 // yield root and change to nobody:bin
219 seteuid(nobody_u
->pw_uid
);
220 setegid(bin_group
->gr_gid
);
222 * Create a test directory under temporary directory with specified
223 * mode permissions and change the gid of test directory to that of
226 if (mkdir(TESTDIR
, MODE_RWX
) < 0) {
227 tst_brkm(TBROK
, cleanup
, "mkdir(2) of %s failed", TESTDIR
);
230 // change to nobody:nobody
231 setegid(nobody_u
->pw_gid
);
233 /* Open the test directory for reading */
234 if ((fd
= open(TESTDIR
, O_RDONLY
)) == -1) {
235 tst_brkm(TBROK
, cleanup
,
236 "open(%s, O_RDONLY) failed, errno=%d : %s",
237 TESTDIR
, errno
, strerror(errno
));
244 * cleanup() - performs all ONE TIME cleanup for this test at
245 * completion or premature exit.
246 * Close the test directory opened in the setup().
247 * Remove the test directory and temporary directory created in
254 * print timing stats if that option was specified.
258 /* Close the test directory opened in the setup() */
259 if (close(fd
) == -1) {
260 tst_brkm(TBROK
, NULL
,
261 "close(%s) Failed, errno=%d : %s",
262 TESTDIR
, errno
, strerror(errno
));
265 /* Remove tmp dir and all files in it */
268 /* exit with return code appropriate for results */
270 } /* End cleanup() */