1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2001 3f08c3bdfSopenharmony_ci * 4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify 5f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by 6f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 7f08c3bdfSopenharmony_ci * (at your option) any later version. 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful, 10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12f08c3bdfSopenharmony_ci * the GNU General Public License for more details. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License 15f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software 16f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci/* 20f08c3bdfSopenharmony_ci * Test Name: lchown02 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * Test Description: 23f08c3bdfSopenharmony_ci * Verify that, 24f08c3bdfSopenharmony_ci * 1) lchown(2) returns -1 and sets errno to EPERM if the effective user id 25f08c3bdfSopenharmony_ci * of process does not match the owner of the file and the process is 26f08c3bdfSopenharmony_ci * not super user. 27f08c3bdfSopenharmony_ci * 2) lchown(2) returns -1 and sets errno to EACCES if search permission is 28f08c3bdfSopenharmony_ci * denied on a component of the path prefix. 29f08c3bdfSopenharmony_ci * 3) lchown(2) returns -1 and sets errno to EFAULT if pathname points 30f08c3bdfSopenharmony_ci * outside user's accessible address space. 31f08c3bdfSopenharmony_ci * 4) lchown(2) returns -1 and sets errno to ENAMETOOLONG if the pathname 32f08c3bdfSopenharmony_ci * component is too long. 33f08c3bdfSopenharmony_ci * 5) lchown(2) returns -1 and sets errno to ENOTDIR if the directory 34f08c3bdfSopenharmony_ci * component in pathname is not a directory. 35f08c3bdfSopenharmony_ci * 6) lchown(2) returns -1 and sets errno to ENOENT if the specified file 36f08c3bdfSopenharmony_ci * does not exists. 37f08c3bdfSopenharmony_ci * 38f08c3bdfSopenharmony_ci * Expected Result: 39f08c3bdfSopenharmony_ci * lchown() should fail with return value -1 and set expected errno. 40f08c3bdfSopenharmony_ci * 41f08c3bdfSopenharmony_ci * HISTORY 42f08c3bdfSopenharmony_ci * 07/2001 Ported by Wayne Boyer 43f08c3bdfSopenharmony_ci * 11/2010 Rewritten by Cyril Hrubis chrubis@suse.cz 44f08c3bdfSopenharmony_ci */ 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#include <stdio.h> 47f08c3bdfSopenharmony_ci#include <stdlib.h> 48f08c3bdfSopenharmony_ci#include <unistd.h> 49f08c3bdfSopenharmony_ci#include <fcntl.h> 50f08c3bdfSopenharmony_ci#include <errno.h> 51f08c3bdfSopenharmony_ci#include <string.h> 52f08c3bdfSopenharmony_ci#include <signal.h> 53f08c3bdfSopenharmony_ci#include <grp.h> 54f08c3bdfSopenharmony_ci#include <pwd.h> 55f08c3bdfSopenharmony_ci#include <sys/types.h> 56f08c3bdfSopenharmony_ci#include <sys/stat.h> 57f08c3bdfSopenharmony_ci#include <sys/mman.h> 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci#include "test.h" 60f08c3bdfSopenharmony_ci#include "safe_macros.h" 61f08c3bdfSopenharmony_ci#include "compat_16.h" 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci#define TEST_USER "nobody" 64f08c3bdfSopenharmony_ci#define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO 65f08c3bdfSopenharmony_ci#define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 66f08c3bdfSopenharmony_ci#define DIR_TEMP "testdir_1" 67f08c3bdfSopenharmony_ci#define TEST_FILE1 "tfile_1" 68f08c3bdfSopenharmony_ci#define SFILE1 "sfile_1" 69f08c3bdfSopenharmony_ci#define TEST_FILE2 "testdir_1/tfile_2" 70f08c3bdfSopenharmony_ci#define SFILE2 "testdir_1/sfile_2" 71f08c3bdfSopenharmony_ci#define TFILE3 "t_file" 72f08c3bdfSopenharmony_ci#define SFILE3 "t_file/sfile" 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ciTCID_DEFINE(lchown02); 75f08c3bdfSopenharmony_ciint TST_TOTAL = 7; 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_cistatic void setup(void); 78f08c3bdfSopenharmony_cistatic void cleanup(void); 79f08c3bdfSopenharmony_cistatic void setup_eperm(int pos); 80f08c3bdfSopenharmony_cistatic void setup_eacces(int pos); 81f08c3bdfSopenharmony_cistatic void setup_enotdir(int pos); 82f08c3bdfSopenharmony_cistatic void setup_longpath(int pos); 83f08c3bdfSopenharmony_cistatic void setup_efault(int pos); 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_cistatic char path[PATH_MAX + 2]; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_cistruct test_case_t { 88f08c3bdfSopenharmony_ci char *pathname; 89f08c3bdfSopenharmony_ci char *desc; 90f08c3bdfSopenharmony_ci int exp_errno; 91f08c3bdfSopenharmony_ci void (*setup) (int pos); 92f08c3bdfSopenharmony_ci}; 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic struct test_case_t test_cases[] = { 95f08c3bdfSopenharmony_ci {SFILE1, "Process is not owner/root", EPERM, setup_eperm}, 96f08c3bdfSopenharmony_ci {SFILE2, "Search permission denied", EACCES, setup_eacces}, 97f08c3bdfSopenharmony_ci {NULL, "Unaccessible address space", EFAULT, setup_efault}, 98f08c3bdfSopenharmony_ci {path, "Pathname too long", ENAMETOOLONG, setup_longpath}, 99f08c3bdfSopenharmony_ci {SFILE3, "Path contains regular file", ENOTDIR, setup_enotdir}, 100f08c3bdfSopenharmony_ci {"", "Pathname is empty", ENOENT, NULL}, 101f08c3bdfSopenharmony_ci {NULL, NULL, 0, NULL} 102f08c3bdfSopenharmony_ci}; 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_cistatic struct passwd *ltpuser; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 107f08c3bdfSopenharmony_ci{ 108f08c3bdfSopenharmony_ci int lc; 109f08c3bdfSopenharmony_ci uid_t user_id; 110f08c3bdfSopenharmony_ci gid_t group_id; 111f08c3bdfSopenharmony_ci int i; 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci tst_parse_opts(argc, argv, NULL, NULL); 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci setup(); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci user_id = geteuid(); 118f08c3bdfSopenharmony_ci UID16_CHECK(user_id, lchown, cleanup); 119f08c3bdfSopenharmony_ci group_id = getegid(); 120f08c3bdfSopenharmony_ci GID16_CHECK(group_id, lchown, cleanup); 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci for (lc = 0; TEST_LOOPING(lc); lc++) { 123f08c3bdfSopenharmony_ci tst_count = 0; 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci for (i = 0; test_cases[i].desc != NULL; i++) { 126f08c3bdfSopenharmony_ci char *file_name = test_cases[i].pathname; 127f08c3bdfSopenharmony_ci char *test_desc = test_cases[i].desc; 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_ci /* 130f08c3bdfSopenharmony_ci * Call lchown(2) to test different test conditions. 131f08c3bdfSopenharmony_ci * verify that it fails with -1 return value and 132f08c3bdfSopenharmony_ci * sets appropriate errno. 133f08c3bdfSopenharmony_ci */ 134f08c3bdfSopenharmony_ci TEST(LCHOWN(cleanup, file_name, user_id, group_id)); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci /* Check return code from lchown(2) */ 137f08c3bdfSopenharmony_ci if (TEST_RETURN == -1) { 138f08c3bdfSopenharmony_ci if (TEST_ERRNO == test_cases[i].exp_errno) { 139f08c3bdfSopenharmony_ci tst_resm(TPASS, 140f08c3bdfSopenharmony_ci "lchown(2) fails, %s, errno:%d", 141f08c3bdfSopenharmony_ci test_desc, TEST_ERRNO); 142f08c3bdfSopenharmony_ci } else { 143f08c3bdfSopenharmony_ci tst_resm(TFAIL, "lchown(2) fails, %s, " 144f08c3bdfSopenharmony_ci "errno:%d, expected errno:%d", 145f08c3bdfSopenharmony_ci test_desc, TEST_ERRNO, 146f08c3bdfSopenharmony_ci test_cases[i].exp_errno); 147f08c3bdfSopenharmony_ci } 148f08c3bdfSopenharmony_ci } else { 149f08c3bdfSopenharmony_ci tst_resm(TFAIL, "lchown(2) returned %ld, " 150f08c3bdfSopenharmony_ci "expected -1, errno:%d", TEST_RETURN, 151f08c3bdfSopenharmony_ci test_cases[i].exp_errno); 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci } 154f08c3bdfSopenharmony_ci } 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_ci cleanup(); 157f08c3bdfSopenharmony_ci tst_exit(); 158f08c3bdfSopenharmony_ci} 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_cistatic void setup(void) 161f08c3bdfSopenharmony_ci{ 162f08c3bdfSopenharmony_ci int i; 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci tst_sig(FORK, DEF_HANDLER, cleanup); 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci tst_require_root(); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci TEST_PAUSE; 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci /* change euid and gid to nobody */ 171f08c3bdfSopenharmony_ci ltpuser = getpwnam(TEST_USER); 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci if (ltpuser == NULL) 174f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, "getpwnam failed"); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci if (setgid(ltpuser->pw_uid) == -1) 177f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "setgid failed"); 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_ci tst_tmpdir(); 180f08c3bdfSopenharmony_ci 181f08c3bdfSopenharmony_ci for (i = 0; test_cases[i].desc != NULL; i++) 182f08c3bdfSopenharmony_ci if (test_cases[i].setup != NULL) 183f08c3bdfSopenharmony_ci test_cases[i].setup(i); 184f08c3bdfSopenharmony_ci} 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_ci/* 187f08c3bdfSopenharmony_ci * setup_eperm() - setup function for a test condition for which lchown(2) 188f08c3bdfSopenharmony_ci * returns -1 and sets errno to EPERM. 189f08c3bdfSopenharmony_ci * 190f08c3bdfSopenharmony_ci * Create test file and symlink with uid 0. 191f08c3bdfSopenharmony_ci */ 192f08c3bdfSopenharmony_cistatic void setup_eperm(int pos LTP_ATTRIBUTE_UNUSED) 193f08c3bdfSopenharmony_ci{ 194f08c3bdfSopenharmony_ci int fd; 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci /* create a testfile */ 197f08c3bdfSopenharmony_ci if ((fd = open(TEST_FILE1, O_RDWR | O_CREAT, 0666)) == -1) 198f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "open failed"); 199f08c3bdfSopenharmony_ci 200f08c3bdfSopenharmony_ci SAFE_CLOSE(cleanup, fd); 201f08c3bdfSopenharmony_ci 202f08c3bdfSopenharmony_ci /* become root once more */ 203f08c3bdfSopenharmony_ci if (seteuid(0) == -1) 204f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "setuid(0) failed"); 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_ci /* create symling to testfile */ 207f08c3bdfSopenharmony_ci SAFE_SYMLINK(cleanup, TEST_FILE1, SFILE1); 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_ci /* back to the user nobody */ 210f08c3bdfSopenharmony_ci if (seteuid(ltpuser->pw_uid) == -1) 211f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "seteuid(%d) failed", ltpuser->pw_uid); 212f08c3bdfSopenharmony_ci} 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci/* 215f08c3bdfSopenharmony_ci * setup_eaccess() - setup function for a test condition for which lchown(2) 216f08c3bdfSopenharmony_ci * returns -1 and sets errno to EACCES. 217f08c3bdfSopenharmony_ci * 218f08c3bdfSopenharmony_ci * Create a test directory under temporary directory and create a test file 219f08c3bdfSopenharmony_ci * under this directory with mode "0666" permissions. 220f08c3bdfSopenharmony_ci * Modify the mode permissions on test directory such that process will not 221f08c3bdfSopenharmony_ci * have search permissions on test directory. 222f08c3bdfSopenharmony_ci */ 223f08c3bdfSopenharmony_cistatic void setup_eacces(int pos LTP_ATTRIBUTE_UNUSED) 224f08c3bdfSopenharmony_ci{ 225f08c3bdfSopenharmony_ci int fd; 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_ci /* create a test directory */ 228f08c3bdfSopenharmony_ci SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_ci /* create a file under test directory */ 231f08c3bdfSopenharmony_ci if ((fd = open(TEST_FILE2, O_RDWR | O_CREAT, 0666)) == -1) 232f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "open failed"); 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci SAFE_CLOSE(cleanup, fd); 235f08c3bdfSopenharmony_ci 236f08c3bdfSopenharmony_ci /* create a symlink of testfile */ 237f08c3bdfSopenharmony_ci SAFE_SYMLINK(cleanup, TEST_FILE2, SFILE2); 238f08c3bdfSopenharmony_ci 239f08c3bdfSopenharmony_ci /* modify mode permissions on test directory */ 240f08c3bdfSopenharmony_ci SAFE_CHMOD(cleanup, DIR_TEMP, FILE_MODE); 241f08c3bdfSopenharmony_ci} 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_ci/* 244f08c3bdfSopenharmony_ci * setup_efault() -- setup for a test condition where lchown(2) returns -1 and 245f08c3bdfSopenharmony_ci * sets errno to EFAULT. 246f08c3bdfSopenharmony_ci * 247f08c3bdfSopenharmony_ci * Create "bad address" by explicitly mmaping anonymous page that may not be 248f08c3bdfSopenharmony_ci * accesed (see PROT_NONE). 249f08c3bdfSopenharmony_ci */ 250f08c3bdfSopenharmony_cistatic void setup_efault(int pos) 251f08c3bdfSopenharmony_ci{ 252f08c3bdfSopenharmony_ci test_cases[pos].pathname = tst_get_bad_addr(cleanup); 253f08c3bdfSopenharmony_ci} 254f08c3bdfSopenharmony_ci 255f08c3bdfSopenharmony_ci/* 256f08c3bdfSopenharmony_ci * setup_enotdir() - setup function for a test condition for which chown(2) 257f08c3bdfSopenharmony_ci * returns -1 and sets errno to ENOTDIR. 258f08c3bdfSopenharmony_ci * 259f08c3bdfSopenharmony_ci * Create a regular file "t_file" to call lchown(2) on "t_file/sfile" later. 260f08c3bdfSopenharmony_ci */ 261f08c3bdfSopenharmony_cistatic void setup_enotdir(int pos LTP_ATTRIBUTE_UNUSED) 262f08c3bdfSopenharmony_ci{ 263f08c3bdfSopenharmony_ci int fd; 264f08c3bdfSopenharmony_ci 265f08c3bdfSopenharmony_ci /* create a testfile under temporary directory */ 266f08c3bdfSopenharmony_ci if ((fd = open(TFILE3, O_RDWR | O_CREAT, MODE_RWX)) == -1) { 267f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, cleanup, "open(2) %s failed", TFILE3); 268f08c3bdfSopenharmony_ci } 269f08c3bdfSopenharmony_ci 270f08c3bdfSopenharmony_ci SAFE_CLOSE(cleanup, fd); 271f08c3bdfSopenharmony_ci} 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci/* 274f08c3bdfSopenharmony_ci * longpath_setup() - setup to create a node with a name length exceeding 275f08c3bdfSopenharmony_ci * the length of PATH_MAX. 276f08c3bdfSopenharmony_ci */ 277f08c3bdfSopenharmony_cistatic void setup_longpath(int pos) 278f08c3bdfSopenharmony_ci{ 279f08c3bdfSopenharmony_ci memset(test_cases[pos].pathname, 'a', PATH_MAX + 1); 280f08c3bdfSopenharmony_ci test_cases[pos].pathname[PATH_MAX + 1] = '\0'; 281f08c3bdfSopenharmony_ci} 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_cistatic void cleanup(void) 284f08c3bdfSopenharmony_ci{ 285f08c3bdfSopenharmony_ci if (seteuid(0) == -1) { 286f08c3bdfSopenharmony_ci tst_resm(TINFO | TERRNO, 287f08c3bdfSopenharmony_ci "seteuid(2) failed to set the effective uid to 0"); 288f08c3bdfSopenharmony_ci } 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_ci tst_rmdir(); 291f08c3bdfSopenharmony_ci} 292