1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. 3f08c3bdfSopenharmony_ci * 4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or 5f08c3bdfSopenharmony_ci * modify it under the terms of the GNU General Public License as 6f08c3bdfSopenharmony_ci * published by the Free Software Foundation; either version 2 of 7f08c3bdfSopenharmony_ci * the License, or (at your option) any later version. 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, 10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f08c3bdfSopenharmony_ci * 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 the Free Software Foundation, 16f08c3bdfSopenharmony_ci * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17f08c3bdfSopenharmony_ci * 18f08c3bdfSopenharmony_ci * Author: 19f08c3bdfSopenharmony_ci * Alexey Kodanev <alexey.kodanev@oracle.com> 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci * Test checks following preconditions: 22f08c3bdfSopenharmony_ci * 23f08c3bdfSopenharmony_ci * Symlinks 24f08c3bdfSopenharmony_ci * --------- 25f08c3bdfSopenharmony_ci * Users who own sticky world-writable directory can't follow symlinks 26f08c3bdfSopenharmony_ci * inside that directory if their don't own ones. All other users can follow. 27f08c3bdfSopenharmony_ci * 28f08c3bdfSopenharmony_ci * Hardlinks 29f08c3bdfSopenharmony_ci * --------- 30f08c3bdfSopenharmony_ci * Hard links restriction applies only to non-privileged users. Only 31f08c3bdfSopenharmony_ci * non-privileged user can't create hard links to files if he isn't owner 32f08c3bdfSopenharmony_ci * of the file or he doesn't have write access to the file. 33f08c3bdfSopenharmony_ci */ 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#define _GNU_SOURCE 36f08c3bdfSopenharmony_ci#include <sys/types.h> 37f08c3bdfSopenharmony_ci#include <sys/stat.h> 38f08c3bdfSopenharmony_ci#include <pwd.h> 39f08c3bdfSopenharmony_ci#include <unistd.h> 40f08c3bdfSopenharmony_ci#include <stdio.h> 41f08c3bdfSopenharmony_ci#include <stdlib.h> 42f08c3bdfSopenharmony_ci#include <string.h> 43f08c3bdfSopenharmony_ci#include <signal.h> 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_ci#include "test.h" 46f08c3bdfSopenharmony_ci#include "safe_macros.h" 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cichar *TCID = "prot_hsymlinks"; 49f08c3bdfSopenharmony_ciint TST_TOTAL = 396; 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci/* create 3 files and 1 dir in each base dir */ 52f08c3bdfSopenharmony_ci#define MAX_FILES_CREATED 4 53f08c3bdfSopenharmony_ci#define MAX_PATH 128 54f08c3bdfSopenharmony_ci#define MAX_CMD_LEN 64 55f08c3bdfSopenharmony_ci#define MAX_USER_NAME 16 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_cienum { 58f08c3bdfSopenharmony_ci ROOT = 0, 59f08c3bdfSopenharmony_ci TEST_USER, 60f08c3bdfSopenharmony_ci USERS_NUM 61f08c3bdfSopenharmony_ci}; 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci#define BASE_DIR_NUM (USERS_NUM + 1) 64f08c3bdfSopenharmony_ci/* 65f08c3bdfSopenharmony_ci * max test files and directories 66f08c3bdfSopenharmony_ci * that will be created during the test 67f08c3bdfSopenharmony_ci * is't not include symlinks and hardlinks 68f08c3bdfSopenharmony_ci * and base directories 69f08c3bdfSopenharmony_ci */ 70f08c3bdfSopenharmony_ci#define MAX_ENTITIES (MAX_FILES_CREATED * BASE_DIR_NUM) 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_cistruct dir_params { 73f08c3bdfSopenharmony_ci char path[MAX_PATH]; 74f08c3bdfSopenharmony_ci int world_writable; 75f08c3bdfSopenharmony_ci int sticky; 76f08c3bdfSopenharmony_ci int owner; 77f08c3bdfSopenharmony_ci}; 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_cistatic struct dir_params bdirs[BASE_DIR_NUM]; 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_cistatic const char file_ext[] = ".hs"; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_cienum { 84f08c3bdfSopenharmony_ci IS_FILE = 0, 85f08c3bdfSopenharmony_ci IS_DIRECTORY, 86f08c3bdfSopenharmony_ci}; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_cistruct user_file { 89f08c3bdfSopenharmony_ci char path[MAX_PATH]; 90f08c3bdfSopenharmony_ci int is_dir; 91f08c3bdfSopenharmony_ci}; 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistruct test_user { 94f08c3bdfSopenharmony_ci char name[MAX_USER_NAME]; 95f08c3bdfSopenharmony_ci struct user_file file[MAX_ENTITIES]; 96f08c3bdfSopenharmony_ci int num; 97f08c3bdfSopenharmony_ci}; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic struct test_user users[USERS_NUM]; 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_cistruct link_info { 102f08c3bdfSopenharmony_ci char path[MAX_PATH]; 103f08c3bdfSopenharmony_ci int owner; 104f08c3bdfSopenharmony_ci int source_owner; 105f08c3bdfSopenharmony_ci int in_world_write; 106f08c3bdfSopenharmony_ci int in_sticky; 107f08c3bdfSopenharmony_ci int is_dir; 108f08c3bdfSopenharmony_ci int dir_owner; 109f08c3bdfSopenharmony_ci}; 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci/* test flags */ 112f08c3bdfSopenharmony_cienum { 113f08c3bdfSopenharmony_ci CANNOT_FOLLOW = -1, 114f08c3bdfSopenharmony_ci CAN_FOLLOW = 0, 115f08c3bdfSopenharmony_ci}; 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_cienum { 118f08c3bdfSopenharmony_ci CANNOT_CREATE = -1, 119f08c3bdfSopenharmony_ci CAN_CREATE = 0, 120f08c3bdfSopenharmony_ci}; 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_cistatic char *tmp_user_name; 123f08c3bdfSopenharmony_cistatic char *default_user = "hsym"; 124f08c3bdfSopenharmony_cistatic int nflag; 125f08c3bdfSopenharmony_cistatic int skip_cleanup; 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_cistatic const option_t options[] = { 128f08c3bdfSopenharmony_ci {"u:", &nflag, &tmp_user_name}, /* -u #user name */ 129f08c3bdfSopenharmony_ci {"s", &skip_cleanup, NULL}, 130f08c3bdfSopenharmony_ci {NULL, NULL, NULL} 131f08c3bdfSopenharmony_ci}; 132f08c3bdfSopenharmony_ci/* full length of the test tmpdir path in /tmp */ 133f08c3bdfSopenharmony_cistatic size_t cwd_offset; 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_cistatic const char hrdlink_proc_path[] = "/proc/sys/fs/protected_hardlinks"; 136f08c3bdfSopenharmony_cistatic const char symlink_proc_path[] = "/proc/sys/fs/protected_symlinks"; 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_cistatic void help(void); 139f08c3bdfSopenharmony_cistatic void setup(int argc, char *argv[]); 140f08c3bdfSopenharmony_cistatic void cleanup(void); 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_cistatic void test_user_cmd(const char *user_cmd); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_cistatic int disable_protected_slinks; 145f08c3bdfSopenharmony_cistatic int disable_protected_hlinks; 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci/* 148f08c3bdfSopenharmony_ci * changes links restrictions 149f08c3bdfSopenharmony_ci * @param value can be: 150f08c3bdfSopenharmony_ci * 0 - restrictions is off 151f08c3bdfSopenharmony_ci * 1 - restrictions is on 152f08c3bdfSopenharmony_ci */ 153f08c3bdfSopenharmony_cistatic void switch_protected_slinks(int value); 154f08c3bdfSopenharmony_cistatic void switch_protected_hlinks(int value); 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_cistatic int get_protected_slinks(void); 157f08c3bdfSopenharmony_cistatic int get_protected_hlinks(void); 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_cistatic void create_link_path(char *buffer, int size, const char *path); 160f08c3bdfSopenharmony_cistatic int create_check_hlinks(const struct user_file *ufile, int owner); 161f08c3bdfSopenharmony_cistatic int create_check_slinks(const struct user_file *ufile, int owner); 162f08c3bdfSopenharmony_cistatic int check_symlink(const struct link_info *li); 163f08c3bdfSopenharmony_cistatic int try_open(const char *name, int mode); 164f08c3bdfSopenharmony_ci/* try to open symlink in diff modes */ 165f08c3bdfSopenharmony_cistatic int try_symlink(const char *name); 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_cistatic int test_run(void); 168f08c3bdfSopenharmony_cistatic void init_base_dirs(void); 169f08c3bdfSopenharmony_cistatic void init_files_dirs(void); 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci/* change effective user id and group id by name 172f08c3bdfSopenharmony_ci * pass NULL to set root 173f08c3bdfSopenharmony_ci */ 174f08c3bdfSopenharmony_cistatic void set_user(const char *name); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci/* add new created files to user struct */ 177f08c3bdfSopenharmony_cistatic void ufiles_add(int usr, char *path, int type); 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 180f08c3bdfSopenharmony_ci{ 181f08c3bdfSopenharmony_ci setup(argc, argv); 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci test_run(); 184f08c3bdfSopenharmony_ci 185f08c3bdfSopenharmony_ci cleanup(); 186f08c3bdfSopenharmony_ci 187f08c3bdfSopenharmony_ci tst_exit(); 188f08c3bdfSopenharmony_ci} 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_cistatic void setup(int argc, char *argv[]) 191f08c3bdfSopenharmony_ci{ 192f08c3bdfSopenharmony_ci tst_parse_opts(argc, argv, options, &help); 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci tst_require_root(); 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci if (eaccess("/etc/passwd", W_OK)) { 197f08c3bdfSopenharmony_ci tst_brkm(TCONF, NULL, 198f08c3bdfSopenharmony_ci "/etc/passwd is not accessible"); 199f08c3bdfSopenharmony_ci } 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci /* initialize user names */ 202f08c3bdfSopenharmony_ci strcpy(users[ROOT].name, "root"); 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci if (tmp_user_name == NULL) 205f08c3bdfSopenharmony_ci tmp_user_name = default_user; 206f08c3bdfSopenharmony_ci snprintf(users[TEST_USER].name, MAX_USER_NAME, "%s", tmp_user_name); 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci tst_sig(FORK, DEF_HANDLER, cleanup); 209f08c3bdfSopenharmony_ci 210f08c3bdfSopenharmony_ci test_user_cmd("useradd"); 211f08c3bdfSopenharmony_ci /* 212f08c3bdfSopenharmony_ci * enable hardlinks and symlinks restrictions, 213f08c3bdfSopenharmony_ci * it's not defualt but have to check 214f08c3bdfSopenharmony_ci */ 215f08c3bdfSopenharmony_ci if (!get_protected_hlinks()) { 216f08c3bdfSopenharmony_ci switch_protected_hlinks(1); 217f08c3bdfSopenharmony_ci disable_protected_hlinks = 1; 218f08c3bdfSopenharmony_ci } 219f08c3bdfSopenharmony_ci if (!get_protected_slinks()) { 220f08c3bdfSopenharmony_ci switch_protected_slinks(1); 221f08c3bdfSopenharmony_ci disable_protected_slinks = 1; 222f08c3bdfSopenharmony_ci } 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_ci tst_tmpdir(); 225f08c3bdfSopenharmony_ci 226f08c3bdfSopenharmony_ci /* fix for hsym user with umask 0077 */ 227f08c3bdfSopenharmony_ci umask(0); 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_ci init_base_dirs(); 230f08c3bdfSopenharmony_ci 231f08c3bdfSopenharmony_ci init_files_dirs(); 232f08c3bdfSopenharmony_ci} 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_cistatic int test_run(void) 235f08c3bdfSopenharmony_ci{ 236f08c3bdfSopenharmony_ci tst_resm(TINFO, " --- HARDLINKS AND SYMLINKS RESTRICTIONS TEST ---"); 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_ci int result_slink = 0, 239f08c3bdfSopenharmony_ci result_hlink = 0, 240f08c3bdfSopenharmony_ci usr, 241f08c3bdfSopenharmony_ci file; 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_ci const struct user_file *ufile; 244f08c3bdfSopenharmony_ci /* 245f08c3bdfSopenharmony_ci * create symlinks and hardlinks from each user's files 246f08c3bdfSopenharmony_ci * to each world writable directory 247f08c3bdfSopenharmony_ci */ 248f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 249f08c3bdfSopenharmony_ci /* get all users files and directories */ 250f08c3bdfSopenharmony_ci for (file = 0; file < users[usr].num; ++file) { 251f08c3bdfSopenharmony_ci ufile = &users[usr].file[file]; 252f08c3bdfSopenharmony_ci result_slink |= create_check_slinks(ufile, usr); 253f08c3bdfSopenharmony_ci result_hlink |= create_check_hlinks(ufile, usr); 254f08c3bdfSopenharmony_ci } 255f08c3bdfSopenharmony_ci } 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ci /* final results */ 258f08c3bdfSopenharmony_ci tst_resm(TINFO, "All test-cases have been completed, summary:" 259f08c3bdfSopenharmony_ci " - symlinks test:\t%s" 260f08c3bdfSopenharmony_ci " - hardlinks test:\t%s", 261f08c3bdfSopenharmony_ci (result_slink == 1) ? "FAIL" : "PASS", 262f08c3bdfSopenharmony_ci (result_hlink == 1) ? "FAIL" : "PASS"); 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_ci return result_slink | result_hlink; 265f08c3bdfSopenharmony_ci} 266f08c3bdfSopenharmony_ci 267f08c3bdfSopenharmony_cistatic void cleanup(void) 268f08c3bdfSopenharmony_ci{ 269f08c3bdfSopenharmony_ci /* call cleanup function only once */ 270f08c3bdfSopenharmony_ci static int first_call = 1; 271f08c3bdfSopenharmony_ci if (!first_call) 272f08c3bdfSopenharmony_ci return; 273f08c3bdfSopenharmony_ci first_call = 0; 274f08c3bdfSopenharmony_ci 275f08c3bdfSopenharmony_ci set_user(NULL); 276f08c3bdfSopenharmony_ci 277f08c3bdfSopenharmony_ci if (skip_cleanup) 278f08c3bdfSopenharmony_ci return; 279f08c3bdfSopenharmony_ci 280f08c3bdfSopenharmony_ci test_user_cmd("userdel -r"); 281f08c3bdfSopenharmony_ci 282f08c3bdfSopenharmony_ci if (disable_protected_hlinks) { 283f08c3bdfSopenharmony_ci tst_resm(TINFO, "Disable protected hardlinks mode back"); 284f08c3bdfSopenharmony_ci switch_protected_hlinks(0); 285f08c3bdfSopenharmony_ci } 286f08c3bdfSopenharmony_ci if (disable_protected_slinks) { 287f08c3bdfSopenharmony_ci tst_resm(TINFO, "Disable protected symlinks mode back"); 288f08c3bdfSopenharmony_ci switch_protected_slinks(0); 289f08c3bdfSopenharmony_ci } 290f08c3bdfSopenharmony_ci 291f08c3bdfSopenharmony_ci tst_rmdir(); 292f08c3bdfSopenharmony_ci} 293f08c3bdfSopenharmony_ci 294f08c3bdfSopenharmony_cistatic int get_protected_hlinks(void) 295f08c3bdfSopenharmony_ci{ 296f08c3bdfSopenharmony_ci int value = 0; 297f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(cleanup, hrdlink_proc_path, "%d", &value); 298f08c3bdfSopenharmony_ci return value; 299f08c3bdfSopenharmony_ci} 300f08c3bdfSopenharmony_ci 301f08c3bdfSopenharmony_cistatic int get_protected_slinks(void) 302f08c3bdfSopenharmony_ci{ 303f08c3bdfSopenharmony_ci int value = 0; 304f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(cleanup, symlink_proc_path, "%d", &value); 305f08c3bdfSopenharmony_ci return value; 306f08c3bdfSopenharmony_ci} 307f08c3bdfSopenharmony_ci 308f08c3bdfSopenharmony_cistatic void switch_protected_hlinks(int value) 309f08c3bdfSopenharmony_ci{ 310f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(cleanup, hrdlink_proc_path, "%d", value == 1); 311f08c3bdfSopenharmony_ci} 312f08c3bdfSopenharmony_ci 313f08c3bdfSopenharmony_cistatic void switch_protected_slinks(int value) 314f08c3bdfSopenharmony_ci{ 315f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(cleanup, symlink_proc_path, "%d", value == 1); 316f08c3bdfSopenharmony_ci} 317f08c3bdfSopenharmony_ci 318f08c3bdfSopenharmony_cistatic void test_user_cmd(const char *user_cmd) 319f08c3bdfSopenharmony_ci{ 320f08c3bdfSopenharmony_ci char cmd[MAX_CMD_LEN]; 321f08c3bdfSopenharmony_ci snprintf(cmd, MAX_CMD_LEN, "%s %s", user_cmd, users[TEST_USER].name); 322f08c3bdfSopenharmony_ci if (system(cmd) != 0) { 323f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, "Failed to run cmd: %s %s", 324f08c3bdfSopenharmony_ci user_cmd, users[TEST_USER].name); 325f08c3bdfSopenharmony_ci } 326f08c3bdfSopenharmony_ci} 327f08c3bdfSopenharmony_ci 328f08c3bdfSopenharmony_cistatic void help(void) 329f08c3bdfSopenharmony_ci{ 330f08c3bdfSopenharmony_ci printf(" -s Skip cleanup.\n"); 331f08c3bdfSopenharmony_ci printf(" -u #user name : Define test user\n"); 332f08c3bdfSopenharmony_ci} 333f08c3bdfSopenharmony_ci 334f08c3bdfSopenharmony_cistatic void create_sub_dir(const char *path, 335f08c3bdfSopenharmony_ci struct dir_params *bdir, mode_t mode) 336f08c3bdfSopenharmony_ci{ 337f08c3bdfSopenharmony_ci snprintf(bdir->path, MAX_PATH, "%s/tmp_%s", 338f08c3bdfSopenharmony_ci path, users[bdir->owner].name); 339f08c3bdfSopenharmony_ci SAFE_MKDIR(cleanup, bdir->path, mode); 340f08c3bdfSopenharmony_ci 341f08c3bdfSopenharmony_ci if (bdir->sticky) 342f08c3bdfSopenharmony_ci mode |= S_ISVTX; 343f08c3bdfSopenharmony_ci chmod(bdir->path, mode); 344f08c3bdfSopenharmony_ci} 345f08c3bdfSopenharmony_ci 346f08c3bdfSopenharmony_cistatic void init_base_dirs(void) 347f08c3bdfSopenharmony_ci{ 348f08c3bdfSopenharmony_ci char *cwd = tst_get_tmpdir(); 349f08c3bdfSopenharmony_ci cwd_offset = strlen(cwd); 350f08c3bdfSopenharmony_ci 351f08c3bdfSopenharmony_ci mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; 352f08c3bdfSopenharmony_ci chmod(cwd, mode); 353f08c3bdfSopenharmony_ci 354f08c3bdfSopenharmony_ci strcpy(bdirs[0].path, cwd); 355f08c3bdfSopenharmony_ci free(cwd); 356f08c3bdfSopenharmony_ci 357f08c3bdfSopenharmony_ci bdirs[0].sticky = 0; 358f08c3bdfSopenharmony_ci bdirs[0].world_writable = 1; 359f08c3bdfSopenharmony_ci 360f08c3bdfSopenharmony_ci /* create subdir for each user */ 361f08c3bdfSopenharmony_ci int dir, usr; 362f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 363f08c3bdfSopenharmony_ci set_user(users[usr].name); 364f08c3bdfSopenharmony_ci dir = usr + 1; 365f08c3bdfSopenharmony_ci bdirs[dir].sticky = 1; 366f08c3bdfSopenharmony_ci bdirs[dir].world_writable = 1; 367f08c3bdfSopenharmony_ci bdirs[dir].owner = usr; 368f08c3bdfSopenharmony_ci 369f08c3bdfSopenharmony_ci create_sub_dir(bdirs[0].path, &bdirs[dir], mode); 370f08c3bdfSopenharmony_ci } 371f08c3bdfSopenharmony_ci} 372f08c3bdfSopenharmony_ci 373f08c3bdfSopenharmony_cistatic void init_files_dirs(void) 374f08c3bdfSopenharmony_ci{ 375f08c3bdfSopenharmony_ci unsigned int dir, usr; 376f08c3bdfSopenharmony_ci /* create all other dirs and files */ 377f08c3bdfSopenharmony_ci for (dir = 0; dir < ARRAY_SIZE(bdirs); ++dir) { 378f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 379f08c3bdfSopenharmony_ci set_user(users[usr].name); 380f08c3bdfSopenharmony_ci char path[MAX_PATH]; 381f08c3bdfSopenharmony_ci 382f08c3bdfSopenharmony_ci /* create file in the main directory */ 383f08c3bdfSopenharmony_ci snprintf(path, MAX_PATH, "%s/%s%s", 384f08c3bdfSopenharmony_ci bdirs[dir].path, users[usr].name, file_ext); 385f08c3bdfSopenharmony_ci ufiles_add(usr, path, IS_FILE); 386f08c3bdfSopenharmony_ci 387f08c3bdfSopenharmony_ci /* create file with S_IWOTH bit set */ 388f08c3bdfSopenharmony_ci strcat(path, "_w"); 389f08c3bdfSopenharmony_ci ufiles_add(usr, path, IS_FILE); 390f08c3bdfSopenharmony_ci 391f08c3bdfSopenharmony_ci chmod(path, S_IRUSR | S_IRGRP | S_IWOTH | S_IROTH); 392f08c3bdfSopenharmony_ci 393f08c3bdfSopenharmony_ci /* create sub directory */ 394f08c3bdfSopenharmony_ci snprintf(path, MAX_PATH, "%s/%s", bdirs[dir].path, 395f08c3bdfSopenharmony_ci users[usr].name); 396f08c3bdfSopenharmony_ci ufiles_add(usr, path, IS_DIRECTORY); 397f08c3bdfSopenharmony_ci 398f08c3bdfSopenharmony_ci /* create local file inside sub directory */ 399f08c3bdfSopenharmony_ci snprintf(path + strlen(path), MAX_PATH - strlen(path), 400f08c3bdfSopenharmony_ci "/local_%s%s", users[usr].name, file_ext); 401f08c3bdfSopenharmony_ci ufiles_add(usr, path, IS_FILE); 402f08c3bdfSopenharmony_ci } 403f08c3bdfSopenharmony_ci } 404f08c3bdfSopenharmony_ci} 405f08c3bdfSopenharmony_ci 406f08c3bdfSopenharmony_cistatic void ufiles_add(int usr, char *path, int type) 407f08c3bdfSopenharmony_ci{ 408f08c3bdfSopenharmony_ci int file = users[usr].num; 409f08c3bdfSopenharmony_ci 410f08c3bdfSopenharmony_ci if (file >= MAX_ENTITIES) 411f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, "Unexpected number of files"); 412f08c3bdfSopenharmony_ci 413f08c3bdfSopenharmony_ci struct user_file *ufile = &users[usr].file[file]; 414f08c3bdfSopenharmony_ci 415f08c3bdfSopenharmony_ci if (type == IS_FILE) 416f08c3bdfSopenharmony_ci SAFE_TOUCH(cleanup, path, 0644, NULL); 417f08c3bdfSopenharmony_ci else 418f08c3bdfSopenharmony_ci SAFE_MKDIR(cleanup, path, 0755); 419f08c3bdfSopenharmony_ci 420f08c3bdfSopenharmony_ci strcpy(ufile->path, path); 421f08c3bdfSopenharmony_ci 422f08c3bdfSopenharmony_ci ufile->is_dir = (type == IS_DIRECTORY); 423f08c3bdfSopenharmony_ci ++users[usr].num; 424f08c3bdfSopenharmony_ci} 425f08c3bdfSopenharmony_ci 426f08c3bdfSopenharmony_cistatic void create_link_path(char *buffer, int size, const char *path) 427f08c3bdfSopenharmony_ci{ 428f08c3bdfSopenharmony_ci /* to make sure name is unique */ 429f08c3bdfSopenharmony_ci static int count; 430f08c3bdfSopenharmony_ci ++count; 431f08c3bdfSopenharmony_ci 432f08c3bdfSopenharmony_ci /* construct link name */ 433f08c3bdfSopenharmony_ci snprintf(buffer, size, "%s/link_%d", path, count); 434f08c3bdfSopenharmony_ci} 435f08c3bdfSopenharmony_ci 436f08c3bdfSopenharmony_cistatic int create_check_slinks(const struct user_file *ufile, int owner) 437f08c3bdfSopenharmony_ci{ 438f08c3bdfSopenharmony_ci int result = 0, usr; 439f08c3bdfSopenharmony_ci unsigned int dir; 440f08c3bdfSopenharmony_ci for (dir = 0; dir < ARRAY_SIZE(bdirs); ++dir) { 441f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 442f08c3bdfSopenharmony_ci /* set user who will create symlink */ 443f08c3bdfSopenharmony_ci set_user(users[usr].name); 444f08c3bdfSopenharmony_ci 445f08c3bdfSopenharmony_ci struct link_info slink_info; 446f08c3bdfSopenharmony_ci create_link_path(slink_info.path, MAX_PATH, 447f08c3bdfSopenharmony_ci bdirs[dir].path); 448f08c3bdfSopenharmony_ci 449f08c3bdfSopenharmony_ci slink_info.owner = usr; 450f08c3bdfSopenharmony_ci slink_info.source_owner = owner; 451f08c3bdfSopenharmony_ci slink_info.in_world_write = bdirs[dir].world_writable; 452f08c3bdfSopenharmony_ci slink_info.in_sticky = bdirs[dir].sticky; 453f08c3bdfSopenharmony_ci slink_info.dir_owner = bdirs[dir].owner; 454f08c3bdfSopenharmony_ci 455f08c3bdfSopenharmony_ci SAFE_SYMLINK(cleanup, ufile->path, slink_info.path); 456f08c3bdfSopenharmony_ci result |= check_symlink(&slink_info); 457f08c3bdfSopenharmony_ci } 458f08c3bdfSopenharmony_ci } 459f08c3bdfSopenharmony_ci return result; 460f08c3bdfSopenharmony_ci} 461f08c3bdfSopenharmony_ci 462f08c3bdfSopenharmony_cistatic int create_check_hlinks(const struct user_file *ufile, int owner) 463f08c3bdfSopenharmony_ci{ 464f08c3bdfSopenharmony_ci int result = 0, usr; 465f08c3bdfSopenharmony_ci unsigned int dir; 466f08c3bdfSopenharmony_ci for (dir = 0; dir < ARRAY_SIZE(bdirs); ++dir) { 467f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 468f08c3bdfSopenharmony_ci /* can't create hardlink to directory */ 469f08c3bdfSopenharmony_ci if (ufile->is_dir) 470f08c3bdfSopenharmony_ci continue; 471f08c3bdfSopenharmony_ci /* set user who will create hardlink */ 472f08c3bdfSopenharmony_ci set_user(users[usr].name); 473f08c3bdfSopenharmony_ci 474f08c3bdfSopenharmony_ci struct link_info hlink_info; 475f08c3bdfSopenharmony_ci create_link_path(hlink_info.path, MAX_PATH, 476f08c3bdfSopenharmony_ci bdirs[dir].path); 477f08c3bdfSopenharmony_ci 478f08c3bdfSopenharmony_ci int can_write = try_open(ufile->path, O_WRONLY) == 0; 479f08c3bdfSopenharmony_ci 480f08c3bdfSopenharmony_ci int tst_flag = (can_write || usr == owner || 481f08c3bdfSopenharmony_ci usr == ROOT) ? CAN_CREATE : CANNOT_CREATE; 482f08c3bdfSopenharmony_ci 483f08c3bdfSopenharmony_ci int fail; 484f08c3bdfSopenharmony_ci fail = tst_flag != link(ufile->path, hlink_info.path); 485f08c3bdfSopenharmony_ci 486f08c3bdfSopenharmony_ci result |= fail; 487f08c3bdfSopenharmony_ci tst_resm((fail) ? TFAIL : TPASS, 488f08c3bdfSopenharmony_ci "Expect: %s create hardlink '...%s' to '...%s', " 489f08c3bdfSopenharmony_ci "owner '%s', curr.user '%s', w(%d)", 490f08c3bdfSopenharmony_ci (tst_flag == CAN_CREATE) ? "can" : "can't", 491f08c3bdfSopenharmony_ci ufile->path + cwd_offset, 492f08c3bdfSopenharmony_ci hlink_info.path + cwd_offset, 493f08c3bdfSopenharmony_ci users[owner].name, users[usr].name, 494f08c3bdfSopenharmony_ci can_write); 495f08c3bdfSopenharmony_ci } 496f08c3bdfSopenharmony_ci } 497f08c3bdfSopenharmony_ci return result; 498f08c3bdfSopenharmony_ci} 499f08c3bdfSopenharmony_ci 500f08c3bdfSopenharmony_cistatic int check_symlink(const struct link_info *li) 501f08c3bdfSopenharmony_ci{ 502f08c3bdfSopenharmony_ci int symlink_result = 0; 503f08c3bdfSopenharmony_ci int usr; 504f08c3bdfSopenharmony_ci for (usr = 0; usr < USERS_NUM; ++usr) { 505f08c3bdfSopenharmony_ci set_user(users[usr].name); 506f08c3bdfSopenharmony_ci int tst_flag = (usr == li->dir_owner && 507f08c3bdfSopenharmony_ci li->in_world_write && li->in_sticky && 508f08c3bdfSopenharmony_ci usr != li->owner) ? CANNOT_FOLLOW : CAN_FOLLOW; 509f08c3bdfSopenharmony_ci 510f08c3bdfSopenharmony_ci int fail = tst_flag != try_symlink(li->path); 511f08c3bdfSopenharmony_ci 512f08c3bdfSopenharmony_ci symlink_result |= fail; 513f08c3bdfSopenharmony_ci 514f08c3bdfSopenharmony_ci tst_resm((fail) ? TFAIL : TPASS, 515f08c3bdfSopenharmony_ci "Expect: %s follow symlink '...%s', " 516f08c3bdfSopenharmony_ci "owner '%s', src.owner '%s', " 517f08c3bdfSopenharmony_ci "curr.user '%s', dir.owner '%s'", 518f08c3bdfSopenharmony_ci (tst_flag == CAN_FOLLOW) ? "can" : "can't", 519f08c3bdfSopenharmony_ci li->path + cwd_offset, users[li->owner].name, 520f08c3bdfSopenharmony_ci users[li->source_owner].name, users[usr].name, 521f08c3bdfSopenharmony_ci users[li->dir_owner].name); 522f08c3bdfSopenharmony_ci } 523f08c3bdfSopenharmony_ci return symlink_result; 524f08c3bdfSopenharmony_ci} 525f08c3bdfSopenharmony_ci 526f08c3bdfSopenharmony_ci/* differenet modes to try in the test */ 527f08c3bdfSopenharmony_cistatic const int o_modes[] = { 528f08c3bdfSopenharmony_ci O_RDONLY, 529f08c3bdfSopenharmony_ci O_WRONLY, 530f08c3bdfSopenharmony_ci O_RDWR, 531f08c3bdfSopenharmony_ci O_RDONLY | O_NONBLOCK | O_DIRECTORY, 532f08c3bdfSopenharmony_ci}; 533f08c3bdfSopenharmony_ci 534f08c3bdfSopenharmony_cistatic int try_symlink(const char *name) 535f08c3bdfSopenharmony_ci{ 536f08c3bdfSopenharmony_ci unsigned int mode; 537f08c3bdfSopenharmony_ci for (mode = 0; mode < ARRAY_SIZE(o_modes); ++mode) { 538f08c3bdfSopenharmony_ci if (try_open(name, o_modes[mode]) != -1) 539f08c3bdfSopenharmony_ci return CAN_FOLLOW; 540f08c3bdfSopenharmony_ci } 541f08c3bdfSopenharmony_ci 542f08c3bdfSopenharmony_ci return CANNOT_FOLLOW; 543f08c3bdfSopenharmony_ci} 544f08c3bdfSopenharmony_ci 545f08c3bdfSopenharmony_cistatic int try_open(const char *name, int mode) 546f08c3bdfSopenharmony_ci{ 547f08c3bdfSopenharmony_ci int fd = open(name, mode); 548f08c3bdfSopenharmony_ci 549f08c3bdfSopenharmony_ci if (fd == -1) 550f08c3bdfSopenharmony_ci return fd; 551f08c3bdfSopenharmony_ci 552f08c3bdfSopenharmony_ci SAFE_CLOSE(cleanup, fd); 553f08c3bdfSopenharmony_ci 554f08c3bdfSopenharmony_ci return 0; 555f08c3bdfSopenharmony_ci} 556f08c3bdfSopenharmony_ci 557f08c3bdfSopenharmony_cistatic void set_user(const char *name) 558f08c3bdfSopenharmony_ci{ 559f08c3bdfSopenharmony_ci uid_t user_id = 0; 560f08c3bdfSopenharmony_ci gid_t user_gr = 0; 561f08c3bdfSopenharmony_ci 562f08c3bdfSopenharmony_ci if (name != NULL) { 563f08c3bdfSopenharmony_ci struct passwd *pswd = getpwnam(name); 564f08c3bdfSopenharmony_ci 565f08c3bdfSopenharmony_ci if (pswd == 0) { 566f08c3bdfSopenharmony_ci tst_brkm(TBROK, cleanup, 567f08c3bdfSopenharmony_ci "Failed to find user '%s'", name); 568f08c3bdfSopenharmony_ci } 569f08c3bdfSopenharmony_ci user_id = pswd->pw_uid; 570f08c3bdfSopenharmony_ci user_gr = pswd->pw_gid; 571f08c3bdfSopenharmony_ci } 572f08c3bdfSopenharmony_ci 573f08c3bdfSopenharmony_ci SAFE_SETEGID(cleanup, user_gr); 574f08c3bdfSopenharmony_ci SAFE_SETEUID(cleanup, user_id); 575f08c3bdfSopenharmony_ci} 576