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  *	rename12
     23  *
     24  * DESCRIPTION
     25  *      check rename() fails with EPERM or 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  *              create a directory fdir and set the sticky bit
     36  *              create file fname under fdir
     37  *              fork a child
     38  *                      set to nobody
     39  *                      try to rename fname to mname
     40  *                      check the return value, if succeeded (return=0)
     41  *			       Log the errno and Issue a FAIL message.
     42  *		        Otherwise,
     43  *			       Verify the errno
     44  *			       if equals to EPERMS or EACCES,
     45  *				       Issue Pass message.
     46  *			       Otherwise,
     47  *				       Issue Fail message.
     48  *	Cleanup:
     49  *		Print errno log and/or timing stats if options given
     50  *		Delete the temporary directory created.
     51  * USAGE
     52  *	rename12 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     53  *	where,  -c n : Run n copies concurrently.
     54  *		-e   : Turn on errno logging.
     55  *		-i n : Execute test n times.
     56  *		-I x : Execute test for x seconds.
     57  *		-P x : Pause for x seconds between iterations.
     58  *		-t   : Turn on syscall timing.
     59  *
     60  * HISTORY
     61  *	07/2001 Ported by Wayne Boyer
     62  *
     63  * RESTRICTIONS
     64  *	Must run test as root.
     65  *
     66  */
     67 #include <errno.h>
     68 #include <sys/stat.h>
     69 #include <sys/types.h>
     70 #include <sys/wait.h>
     71 #include <fcntl.h>
     72 #include <pwd.h>
     73 #include <unistd.h>
     74 
     75 #include "test.h"
     76 #include "safe_macros.h"
     77 
     78 void setup();
     79 void cleanup();
     80 
     81 #define PERMS		0777
     82 
     83 char *TCID = "rename12";
     84 int TST_TOTAL = 1;
     85 
     86 int fd;
     87 char fdir[255];
     88 char fname[255], mname[255];
     89 uid_t nobody_uid;
     90 struct stat buf1;
     91 
     92 int main(int ac, char **av)
     93 {
     94 	int lc;
     95 	pid_t pid;
     96 	int status;
     97 
     98 	/*
     99 	 * parse standard options
    100 	 */
    101 	tst_parse_opts(ac, av, NULL, NULL);
    102 
    103 	/*
    104 	 * perform global setup for test
    105 	 */
    106 	setup();
    107 
    108 	/*
    109 	 * check looping state if -i option given
    110 	 */
    111 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    112 
    113 		tst_count = 0;
    114 
    115 		/*
    116 		 * rename a file whose parent directory has
    117 		 * the sticky bit set without root permission
    118 		 * or effective uid
    119 		 */
    120 
    121 		if ((pid = FORK_OR_VFORK()) == -1) {
    122 			tst_brkm(TBROK, cleanup, "fork() failed");
    123 		}
    124 
    125 		if (pid == 0) {	/* child */
    126 			/* set to nobody */
    127 			if (seteuid(nobody_uid) == -1) {
    128 				tst_resm(TWARN, "setreuid failed");
    129 				perror("setreuid");
    130 				exit(1);
    131 			}
    132 
    133 			/* rename "old" to "new" */
    134 			TEST(rename(fname, mname));
    135 
    136 			if (TEST_RETURN != -1) {
    137 				tst_resm(TFAIL, "call succeeded unexpectedly");
    138 				exit(1);
    139 			}
    140 
    141 			if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) {
    142 				tst_resm(TFAIL,
    143 					 "Expected EPERM or EACCES, got %d",
    144 					 TEST_ERRNO);
    145 				exit(1);
    146 			} else {
    147 				tst_resm(TPASS,
    148 					 "rename returned EPERM or EACCES");
    149 			}
    150 
    151 			/* set the id back to root */
    152 			if (seteuid(0) == -1) {
    153 				tst_resm(TWARN, "seteuid(0) failed");
    154 			}
    155 		} else {	/* parent */
    156 			wait(&status);
    157 			if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
    158 				exit(WEXITSTATUS(status));
    159 			} else {
    160 				exit(0);
    161 			}
    162 
    163 		}
    164 	}
    165 
    166 	cleanup();
    167 	tst_exit();
    168 
    169 }
    170 
    171 /*
    172  * setup() - performs all ONE TIME setup for this test.
    173  */
    174 void setup(void)
    175 {
    176 	struct passwd *pw;
    177 
    178 	tst_require_root();
    179 
    180 	tst_sig(FORK, DEF_HANDLER, cleanup);
    181 
    182 	pw = SAFE_GETPWNAM(NULL, "nobody");
    183 	nobody_uid = pw->pw_uid;
    184 
    185 	TEST_PAUSE;
    186 
    187 	/* Create a temporary directory and make it current. */
    188 	tst_tmpdir();
    189 
    190 	umask(0);
    191 
    192 	sprintf(fdir, "./tdir_%d", getpid());
    193 	sprintf(fname, "%s/tfile_%d", fdir, getpid());
    194 	sprintf(mname, "%s/rnfile_%d", fdir, getpid());
    195 
    196 	/* create a directory */
    197 	SAFE_MKDIR(cleanup, fdir, PERMS);
    198 
    199 	SAFE_STAT(cleanup, fdir, &buf1);
    200 
    201 	/* set the sticky bit */
    202 	if (chmod(fdir, buf1.st_mode | S_ISVTX) != 0) {
    203 		tst_brkm(TBROK, cleanup, "failed to set the S_ISVTX bit");
    204 
    205 	}
    206 
    207 	/* create a file under fdir */
    208 	SAFE_TOUCH(cleanup, fname, 0700, NULL);
    209 }
    210 
    211 /*
    212  * cleanup() - performs all ONE TIME cleanup for this test at
    213  *             completion or premature exit.
    214  */
    215 void cleanup(void)
    216 {
    217 
    218 	/*
    219 	 * Remove the temporary directory.
    220 	 */
    221 	tst_rmdir();
    222 }
    223