Home | History | Annotate | Download | only in rename
      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  * NAME
     22  *	rename09
     23  *
     24  * DESCRIPTION
     25  *      check rename() fails with EACCES
     26  *
     27  * ALGORITHM
     28  *	Setup:
     29  *		Setup signal handling.
     30  *		Create temporary directory.
     31  *		Pause for SIGUSR1 if option specified.
     32  *
     33  *	Test:
     34  *		Loop if the proper options are given.
     35  *              fork the first child
     36  *                      set to be nobody
     37  *                      create old dir with mode 0700
     38  *                      creat a file under it
     39  *              fork the second child
     40  *                      set to bin
     41  *                      create new dir with mode 0700
     42  *                      create a "new" file under it
     43  *                      try to rename file under old dir to file under new dir
     44  *                      check the return value, if succeeded (return=0)
     45  *			       Issue a FAIL message.
     46  *		        Otherwise,
     47  *			       Log the errno
     48  *			       Verify the errno
     49  *			       if equals to EACCESS,
     50  *				       Issue Pass message.
     51  *			       Otherwise,
     52  *				       Issue Fail message.
     53  *	Cleanup:
     54  *		Print errno log and/or timing stats if options given
     55  *		Delete the temporary directory created.
     56  *
     57  * USAGE
     58  *	rename09 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     59  *	where,  -c n : Run n copies concurrently.
     60  *		-e   : Turn on errno logging.
     61  *		-i n : Execute test n times.
     62  *		-I x : Execute test for x seconds.
     63  *		-P x : Pause for x seconds between iterations.
     64  *		-t   : Turn on syscall timing.
     65  *
     66  * HISTORY
     67  *	07/2001 Ported by Wayne Boyer
     68  *
     69  * RESTRICTIONS
     70  *	Must run test as root.
     71  *
     72  */
     73 #include <errno.h>
     74 #include <sys/types.h>
     75 #include <sys/stat.h>
     76 #include <fcntl.h>
     77 #include <pwd.h>
     78 #include <sys/wait.h>
     79 #include <unistd.h>
     80 
     81 #include "test.h"
     82 #include "safe_macros.h"
     83 
     84 void setup();
     85 void cleanup();
     86 
     87 #define PERMS		0700
     88 
     89 char *TCID = "rename09";
     90 int TST_TOTAL = 1;
     91 
     92 char fdir[255], mdir[255];
     93 char fname[255], mname[255];
     94 uid_t nobody_uid, bin_uid;
     95 
     96 int main(int ac, char **av)
     97 {
     98 	int lc;
     99 	int rval;
    100 	pid_t pid, pid1;
    101 	int status;
    102 
    103 	/*
    104 	 * parse standard options
    105 	 */
    106 	tst_parse_opts(ac, av, NULL, NULL);
    107 
    108 	/*
    109 	 * perform global setup for test
    110 	 */
    111 	setup();
    112 
    113 	/*
    114 	 * check looping state if -i option given
    115 	 */
    116 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    117 
    118 		tst_count = 0;
    119 
    120 		if ((pid = FORK_OR_VFORK()) == -1) {
    121 			tst_brkm(TBROK, cleanup, "fork() #1 failed");
    122 		}
    123 
    124 		if (pid == 0) {	/* first child */
    125 			/* set to nobody */
    126 			rval = setreuid(nobody_uid, nobody_uid);
    127 			if (rval < 0) {
    128 				tst_resm(TWARN, "setreuid failed to "
    129 					 "to set the real uid to %d and "
    130 					 "effective uid to %d",
    131 					 nobody_uid, nobody_uid);
    132 				perror("setreuid");
    133 				exit(1);
    134 			}
    135 
    136 			/* create the a directory with 0700 permits */
    137 			if (mkdir(fdir, PERMS) == -1) {
    138 				tst_resm(TWARN, "mkdir(%s, %#o) Failed",
    139 					 fdir, PERMS);
    140 				exit(1);
    141 			}
    142 
    143 			/* create "old" file under it */
    144 			SAFE_TOUCH(cleanup, fname, 0700, NULL);
    145 
    146 			exit(0);
    147 		}
    148 
    149 		/* wait for child to exit */
    150 		wait(&status);
    151 		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
    152 			tst_brkm(TBROK, cleanup, "First child failed to set "
    153 				 "up conditions for the test");
    154 		}
    155 
    156 		if ((pid1 = FORK_OR_VFORK()) == -1) {
    157 			tst_brkm(TBROK, cleanup, "fork() #2 failed");
    158 		}
    159 
    160 		if (pid1 == 0) {	/* second child */
    161 			/* set to bin */
    162 			if ((rval = seteuid(bin_uid)) == -1) {
    163 				tst_resm(TWARN, "seteuid() failed");
    164 				perror("setreuid");
    165 				exit(1);
    166 			}
    167 
    168 			/* create "new" directory */
    169 			if (mkdir(mdir, PERMS) == -1) {
    170 				tst_resm(TWARN, "mkdir(%s, %#o) failed",
    171 					 mdir, PERMS);
    172 				exit(1);
    173 			}
    174 
    175 			SAFE_TOUCH(cleanup, mname, 0700, NULL);
    176 
    177 			/* rename "old" to "new" */
    178 			TEST(rename(fname, mname));
    179 			if (TEST_RETURN != -1) {
    180 				tst_resm(TFAIL, "call succeeded unexpectedly");
    181 				continue;
    182 			}
    183 
    184 			if (TEST_ERRNO != EACCES) {
    185 				tst_resm(TFAIL, "Expected EACCES got %d",
    186 					 TEST_ERRNO);
    187 			} else {
    188 				tst_resm(TPASS, "rename() returned EACCES");
    189 			}
    190 
    191 			/* set the process id back to root */
    192 			if (seteuid(0) == -1) {
    193 				tst_resm(TWARN, "seteuid(0) failed");
    194 				exit(1);
    195 			}
    196 
    197 			/* clean up things in case we are looping */
    198 			SAFE_UNLINK(cleanup, fname);
    199 			SAFE_UNLINK(cleanup, mname);
    200 			SAFE_RMDIR(cleanup, fdir);
    201 			SAFE_RMDIR(cleanup, mdir);
    202 		} else {
    203 			/* parent - let the second child carry on */
    204 			waitpid(pid1, &status, 0);
    205 			if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
    206 				exit(WEXITSTATUS(status));
    207 			} else {
    208 				exit(0);
    209 			}
    210 		}
    211 	}
    212 
    213 	/*
    214 	 * cleanup and exit
    215 	 */
    216 	cleanup();
    217 	tst_exit();
    218 
    219 }
    220 
    221 /*
    222  * setup() - performs all ONE TIME setup for this test.
    223  */
    224 void setup(void)
    225 {
    226 	struct passwd *pw;
    227 
    228 	tst_require_root();
    229 
    230 	pw = SAFE_GETPWNAM(NULL, "nobody");
    231 	nobody_uid = pw->pw_uid;
    232 	pw = SAFE_GETPWNAM(NULL, "bin");
    233 	bin_uid = pw->pw_uid;
    234 
    235 	tst_sig(FORK, DEF_HANDLER, cleanup);
    236 
    237 	TEST_PAUSE;
    238 
    239 	/* Create a temporary directory and make it current. */
    240 	tst_tmpdir();
    241 
    242 	umask(0);
    243 
    244 	sprintf(fdir, "tdir_%d", getpid());
    245 	sprintf(mdir, "rndir_%d", getpid());
    246 	sprintf(fname, "%s/tfile_%d", fdir, getpid());
    247 	sprintf(mname, "%s/rnfile_%d", mdir, getpid());
    248 }
    249 
    250 /*
    251  * cleanup() - performs all ONE TIME cleanup for this test at
    252  *             completion or premature exit.
    253  */
    254 void cleanup(void)
    255 {
    256 
    257 	/*
    258 	 * Remove the temporary directory.
    259 	 */
    260 	tst_rmdir();
    261 
    262 	/*
    263 	 * Exit with return code appropriate for results.
    264 	 */
    265 
    266 }
    267