/* * * Copyright (c) International Business Machines Corp., 2001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Test Description: * Verify that access() succeeds to check the existence or read/write/execute * permissions on a file if the mode argument passed was F_OK/R_OK/W_OK/X_OK. * * Also verify that, access() succeeds to test the accessibility of the file * referred to by symbolic link if the pathname points to a symbolic link. * * As well as verify that, these test files can be * stat/read/written/executed indeed as root and nobody respectively. * * 07/2001 Ported by Wayne Boyera * 06/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <paths.h> #include "tst_test.h" #define FNAME_F "file_f" #define FNAME_R "file_r" #define FNAME_W "file_w" #define FNAME_X "file_x" #define SNAME_F "symlink_f" #define SNAME_R "symlink_r" #define SNAME_W "symlink_w" #define SNAME_X "symlink_x" static uid_t uid; static struct tcase { const char *pathname; int mode; char *name; const char *targetname; } tcases[] = { {FNAME_F, F_OK, "F_OK", FNAME_F}, {FNAME_R, R_OK, "R_OK", FNAME_R}, {FNAME_W, W_OK, "W_OK", FNAME_W}, {FNAME_X, X_OK, "X_OK", FNAME_X}, {SNAME_F, F_OK, "F_OK", FNAME_F}, {SNAME_R, R_OK, "R_OK", FNAME_R}, {SNAME_W, W_OK, "W_OK", FNAME_W}, {SNAME_X, X_OK, "X_OK", FNAME_X} }; static void access_test(struct tcase *tc, const char *user) { struct stat stat_buf; char command[64]; TEST(access(tc->pathname, tc->mode)); if (TEST_RETURN == -1) { tst_res(TFAIL | TTERRNO, "access(%s, %s) as %s failed", tc->pathname, tc->name, user); return; } switch (tc->mode) { case F_OK: /* * The specified file(or pointed to by symbolic link) * exists, attempt to get its status, if successful, * access() behaviour is correct. */ TEST(stat(tc->targetname, &stat_buf)); if (TEST_RETURN == -1) { tst_res(TFAIL | TTERRNO, "stat(%s) as %s failed", tc->targetname, user); return; } break; case R_OK: /* * The specified file(or pointed to by symbolic link) * has read access, attempt to open the file with O_RDONLY, * if we get a valid fd, access() behaviour is correct. */ TEST(open(tc->targetname, O_RDONLY)); if (TEST_RETURN == -1) { tst_res(TFAIL | TTERRNO, "open %s with O_RDONLY as %s failed", tc->targetname, user); return; } SAFE_CLOSE(TEST_RETURN); break; case W_OK: /* * The specified file(or pointed to by symbolic link) * has write access, attempt to open the file with O_WRONLY, * if we get a valid fd, access() behaviour is correct. */ TEST(open(tc->targetname, O_WRONLY)); if (TEST_RETURN == -1) { tst_res(TFAIL | TTERRNO, "open %s with O_WRONLY as %s failed", tc->targetname, user); return; } SAFE_CLOSE(TEST_RETURN); break; case X_OK: /* * The specified file(or pointed to by symbolic link) * has execute access, attempt to execute the executable * file, if successful, access() behaviour is correct. */ sprintf(command, "./%s", tc->targetname); TEST(system(command)); if (TEST_RETURN != 0) { tst_res(TFAIL | TTERRNO, "execute %s as %s failed", tc->targetname, user); return; } break; default: break; } tst_res(TPASS, "access(%s, %s) as %s behaviour is correct.", tc->pathname, tc->name, user); } static void verify_access(unsigned int n) { struct tcase *tc = &tcases[n]; pid_t pid; /* test as root */ access_test(tc, "root"); /* test as nobody */ pid = SAFE_FORK(); if (pid) { SAFE_WAITPID(pid, NULL, 0); } else { SAFE_SETUID(uid); access_test(tc, "nobody"); } } static void setup(void) { struct passwd *pw; pw = SAFE_GETPWNAM("nobody"); uid = pw->pw_uid; SAFE_TOUCH(FNAME_F, 0000, NULL); SAFE_TOUCH(FNAME_R, 0444, NULL); SAFE_TOUCH(FNAME_W, 0222, NULL); SAFE_TOUCH(FNAME_X, 0555, NULL); SAFE_FILE_PRINTF(FNAME_X, "#!%s\n", _PATH_BSHELL); SAFE_SYMLINK(FNAME_F, SNAME_F); SAFE_SYMLINK(FNAME_R, SNAME_R); SAFE_SYMLINK(FNAME_W, SNAME_W); SAFE_SYMLINK(FNAME_X, SNAME_X); } static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .needs_tmpdir = 1, .needs_root = 1, .forks_child = 1, .setup = setup, .test = verify_access, };