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