1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 07/2001 Ported by Wayne Boyer 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 Foundation, 17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * Test Description: 22 * Verify that, fchown(2) succeeds to change the group of a file specified 23 * by path when called by non-root user with the following constraints, 24 * - euid of the process is equal to the owner of the file. 25 * - the intended gid is either egid, or one of the supplementary gids 26 * of the process. 27 * Also, verify that fchown() clears the setuid/setgid bits set on the file. 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <signal.h> 38 #include <grp.h> 39 #include <pwd.h> 40 41 #include "test.h" 42 #include "safe_macros.h" 43 #include "compat_16.h" 44 45 #define FILE_MODE (mode_t)(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 46 #define NEW_PERMS (mode_t)(S_IFREG | S_IRWXU | S_IRWXG | S_ISUID | S_ISGID) 47 #define FCHOWN_PERMS (mode_t)(NEW_PERMS & ~(S_ISUID | S_ISGID)) 48 #define TESTFILE "testfile" 49 50 TCID_DEFINE(fchown03); 51 int TST_TOTAL = 1; 52 53 static int fildes; 54 char nobody_uid[] = "nobody"; 55 static struct passwd *ltpuser; 56 57 static void setup(void); 58 static void cleanup(void); 59 60 int main(int ac, char **av) 61 { 62 struct stat stat_buf; 63 int lc; 64 uid_t user_id; 65 gid_t group_id; 66 67 tst_parse_opts(ac, av, NULL, NULL); 68 69 setup(); 70 71 for (lc = 0; TEST_LOOPING(lc); lc++) { 72 tst_count = 0; 73 74 user_id = geteuid(); 75 GID16_CHECK((group_id = getegid()), "fchown", cleanup) 76 77 TEST(FCHOWN(cleanup, fildes, -1, group_id)); 78 79 if (TEST_RETURN == -1) { 80 tst_resm(TFAIL, "fchown() on %s Fails, errno=%d", 81 TESTFILE, TEST_ERRNO); 82 continue; 83 } 84 85 SAFE_FSTAT(cleanup, fildes, &stat_buf); 86 87 if ((stat_buf.st_uid != user_id) || 88 (stat_buf.st_gid != group_id)) { 89 tst_resm(TFAIL, "%s: Incorrect " 90 "ownership set, Expected %d %d", 91 TESTFILE, user_id, group_id); 92 continue; 93 } 94 95 if (stat_buf.st_mode != FCHOWN_PERMS) { 96 tst_resm(TFAIL, "%s: Incorrect mode permissions" 97 " %#o, Expected %#o", TESTFILE, 98 stat_buf.st_mode, FCHOWN_PERMS); 99 } else { 100 tst_resm(TPASS, "fchown() on %s succeeds: " 101 "Setuid/gid bits cleared", TESTFILE); 102 } 103 } 104 105 cleanup(); 106 tst_exit(); 107 } 108 109 static void setup(void) 110 { 111 tst_sig(FORK, DEF_HANDLER, cleanup); 112 113 tst_require_root(); 114 115 ltpuser = SAFE_GETPWNAM(cleanup, nobody_uid); 116 SAFE_SETEUID(NULL, ltpuser->pw_uid); 117 118 TEST_PAUSE; 119 120 tst_tmpdir(); 121 122 fildes = SAFE_OPEN(cleanup, TESTFILE, O_RDWR | O_CREAT, FILE_MODE); 123 124 SAFE_SETEUID(cleanup, 0); 125 126 SAFE_FCHOWN(cleanup, fildes, -1, 0); 127 SAFE_FCHMOD(cleanup, fildes, NEW_PERMS); 128 129 SAFE_SETEGID(cleanup, ltpuser->pw_gid); 130 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 131 } 132 133 static void cleanup(void) 134 { 135 if (fildes > 0 && close(fildes)) 136 tst_resm(TWARN | TERRNO, "close(%s) Failed", TESTFILE); 137 138 tst_rmdir(); 139 } 140