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