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 * setresuid03.c 23 * 24 * DESCRIPTION 25 * Test that the setresuid system call sets the proper errno 26 * values when a non-root user attempts to change the real, effective or 27 * saved uid to a value other than one of the current uid, the current 28 * effective uid of the current saved uid. Also verify that setresuid 29 * fails if an invalid uid value is given. 30 * 31 * ALGORITHM 32 * 33 * Setup: 34 * Setup signal handling 35 * Get user information. 36 * Pause for SIGUSER1 if option specified. 37 * 38 * Setup test values. 39 * Loop if the proper options are given. 40 * For each test set execute the system call 41 * Check that we received the expected result. 42 * Verify that the uid, euid and suid values are still correct. 43 * Cleanup: 44 * Print errno log and/or timing stats if option given. 45 * 46 * USAGE: <for command-line> 47 * setresuid03 [-c n] [-f] [-i n] [-I x] [-P x] [-t] 48 * where, -c n : Run n copies concurrently. 49 * -e : Turn on errno logging. 50 * -f : Turn off functionality Testing. 51 * -i n : Execute test n times. 52 * -I x : Execute test for x seconds. 53 * -P x : Pause for x seconds between iterations. 54 * -t : Turn on syscall timing. 55 * 56 * History 57 * 07/2001 John George 58 * -Ported 59 * 60 * Restrictions 61 * This test must be run by root. 62 * nobody and bin must be a valid users. 63 */ 64 65 #define _GNU_SOURCE 1 66 #include <pwd.h> 67 #include <stdlib.h> 68 #include "test.h" 69 #include <errno.h> 70 #include <sys/wait.h> 71 72 #include <compat_16.h> 73 74 TCID_DEFINE(setresuid03); 75 76 uid_t neg_one = -1; 77 78 /* flag to tell parent if child passed or failed. */ 79 int flag = 0; 80 81 uid_t root_pw_uid, nobody_pw_uid, bin_pw_uid; 82 char user1name[] = "nobody"; 83 char user2name[] = "bin"; 84 char rootname[] = "root"; 85 86 struct passwd nobody, bin, root; 87 88 /* 89 * The following structure contains all test data. Each structure in the array 90 * is used for a separate test. The tests are executed in the for loop below. 91 */ 92 93 struct test_data_t { 94 uid_t *real_uid; 95 uid_t *eff_uid; 96 uid_t *sav_uid; 97 int exp_errno; 98 struct passwd *exp_real_usr; 99 struct passwd *exp_eff_usr; 100 struct passwd *exp_sav_usr; 101 char *test_msg; 102 } test_data[] = { 103 { 104 &nobody_pw_uid, &neg_one, &neg_one, EPERM, &root, &bin, &bin, 105 "After setresuid(root, -1, -1),"}, { 106 &neg_one, &neg_one, &nobody_pw_uid, EPERM, &root, &bin, &bin, 107 "After setresuid(-1, -1, bin),"}, { 108 &neg_one, &nobody_pw_uid, &neg_one, EPERM, &root, &bin, &bin, 109 "After setresuid(-1, -1, bin),"} 110 }; 111 112 int TST_TOTAL = sizeof(test_data) / sizeof(test_data[0]); 113 114 void setup(void); 115 void cleanup(void); 116 117 void 118 uid_verify(struct passwd *ru, struct passwd *eu, struct passwd *su, char *); 119 120 int main(int ac, char **av) 121 { 122 int lc; 123 124 tst_parse_opts(ac, av, NULL, NULL); 125 126 setup(); 127 128 for (lc = 0; TEST_LOOPING(lc); lc++) { 129 int i, pid; 130 131 /* reset tst_count in case we are looping */ 132 tst_count = 0; 133 134 /* set the appropriate ownership values */ 135 if (setresuid(root_pw_uid, bin_pw_uid, bin_pw_uid) 136 == -1) { 137 tst_brkm(TFAIL, cleanup, "Initial setresuid failed"); 138 } 139 140 if ((pid = FORK_OR_VFORK()) == -1) { 141 tst_brkm(TBROK, cleanup, "fork failed"); 142 } else if (pid == 0) { /* child */ 143 144 for (i = 0; i < TST_TOTAL; i++) { 145 146 /* Set the real, effective or saved user id */ 147 TEST(SETRESUID(NULL, *test_data[i].real_uid, 148 *test_data[i].eff_uid, 149 *test_data[i].sav_uid)); 150 151 if (TEST_RETURN == -1 && TEST_ERRNO == 152 test_data[i].exp_errno) { 153 tst_resm(TPASS, "setresuid(%d, %d, %d) " 154 "failed as expected.", 155 *test_data[i].real_uid, 156 *test_data[i].eff_uid, 157 *test_data[i].sav_uid); 158 } else { 159 tst_resm(TFAIL, "setresuid(%d, %d, %d) " 160 "did not fail as expected.", 161 *test_data[i].real_uid, 162 *test_data[i].eff_uid, 163 *test_data[i].sav_uid); 164 flag = -1; 165 } 166 167 uid_verify(test_data[i].exp_real_usr, 168 test_data[i].exp_eff_usr, 169 test_data[i].exp_sav_usr, 170 test_data[i].test_msg); 171 } 172 exit(flag); 173 } else { /* parent */ 174 tst_record_childstatus(cleanup, pid); 175 } 176 } 177 cleanup(); 178 tst_exit(); 179 } 180 181 /* 182 * setup() 183 * performs all ONE TIME setup for this test 184 */ 185 void setup(void) 186 { 187 tst_require_root(); 188 189 tst_sig(FORK, DEF_HANDLER, cleanup); 190 191 if (getpwnam("nobody") == NULL) { 192 tst_brkm(TBROK, NULL, "nobody must be a valid user."); 193 } 194 195 if (getpwnam("bin") == NULL) { 196 tst_brkm(TBROK, NULL, "bin must be a valid user."); 197 } 198 199 root = *(getpwnam("root")); 200 UID16_CHECK((root_pw_uid = root.pw_uid), "setresuid", cleanup) 201 202 nobody = *(getpwnam("nobody")); 203 UID16_CHECK((nobody_pw_uid = nobody.pw_uid), "setresuid", cleanup) 204 205 bin = *(getpwnam("bin")); 206 UID16_CHECK((bin_pw_uid = bin.pw_uid), "setresuid", cleanup) 207 208 /* Pause if that option was specified 209 * TEST_PAUSE contains the code to fork the test with the -i option. 210 * You want to make sure you do this before you create your temporary 211 * directory. 212 */ 213 TEST_PAUSE; 214 } 215 216 /* 217 * cleanup() 218 * performs all ONE TIME cleanup for this test at 219 * completion or premature exit 220 */ 221 void cleanup(void) 222 { 223 224 } 225 226 void 227 uid_verify(struct passwd *ru, struct passwd *eu, struct passwd *su, char *when) 228 { 229 uid_t cur_ru, cur_eu, cur_su; 230 if (getresuid(&cur_ru, &cur_eu, &cur_su) != 0) { 231 flag = -1; 232 tst_brkm(TBROK, cleanup, "Set getresuid() failed"); 233 } 234 if ((cur_ru != ru->pw_uid) || (cur_eu != eu->pw_uid) || (cur_su != 235 su->pw_uid)) { 236 tst_resm(TFAIL, "ERROR: %s real uid = %d; effective uid = %d; " 237 "saved uid = %d", when, cur_ru, cur_eu, cur_su); 238 tst_resm(TINFO, "Expected: real uid = %d, effective uid = %d " 239 "saved uid = %d", ru->pw_uid, eu->pw_uid, su->pw_uid); 240 flag = -1; 241 } else { 242 tst_resm(TINFO, "real uid = %d, effective uid = %d, and " 243 "saved uid = %d as expected", cur_ru, cur_eu, cur_su); 244 } 245 } 246