1/*
2 *  This program is free software; you can redistribute it and/or modify
3 *  it under the terms of the GNU General Public License version 2.
4 *
5 *  This program is distributed in the hope that it will be useful,
6 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
7 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8 *  GNU General Public License for more details.
9 *
10 * Test that the owner is unchanged when O_TRUNC is set, the shared memory
11 * object exists and it is successfully opened O_RDWR.
12 *
13 * In most case this test will be unresolved if not run by root.
14 * Steps:
15 *  1. Create a shared memory object.
16 *  2. Set a non zero size for this object (to force the modification of the
17 *     object when it will be reopen with O_TRUNC set).
18 *  3. Set his effective user id to an other user id which is not root.
19 *  4. Call shm_open with O_TRUNC set.
20 *  5. Check that the owner is unchanged.
21 */
22
23/* getpwent() is part of XSI option */
24#define _XOPEN_SOURCE 600
25
26#include <sys/mman.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <pwd.h>
30#include <unistd.h>
31#include <errno.h>
32#include <string.h>
33#include <stdio.h>
34#include "posixtest.h"
35
36#define BUF_SIZE 8
37#define SHM_NAME "posixtest_26-2"
38
39int main(void)
40{
41	int fd;
42	struct stat stat_buf;
43	struct passwd *pw;
44	uid_t old_uid;
45	gid_t old_gid;
46
47	umask(0);
48	fd = shm_open(SHM_NAME, O_RDWR | O_CREAT,
49		      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
50		      S_IWOTH);
51
52	if (fd == -1) {
53		perror("An error occurs when calling shm_open()");
54		return PTS_UNRESOLVED;
55	}
56
57	if (ftruncate(fd, BUF_SIZE) != 0) {
58		perror("An error occurs when calling ftruncate()");
59		shm_unlink(SHM_NAME);
60		return PTS_UNRESOLVED;
61	}
62
63	if (fstat(fd, &stat_buf) != 0) {
64		perror("An error occurs when calling fstat()");
65		shm_unlink(SHM_NAME);
66		return PTS_UNRESOLVED;
67	}
68	old_uid = stat_buf.st_uid;
69	old_gid = stat_buf.st_gid;
70
71	/* search for the first user which is non root and which is not the
72	   current user */
73	while ((pw = getpwent()) != NULL)
74		if (strcmp(pw->pw_name, "root") && pw->pw_uid != getuid())
75			break;
76
77	if (pw == NULL) {
78		printf("There is no other user than current and root.\n");
79		shm_unlink(SHM_NAME);
80		return PTS_UNRESOLVED;
81	}
82
83	if (seteuid(pw->pw_uid) != 0) {
84		if (errno == EPERM) {
85			printf
86			    ("You don't have permission to change your UID.\nTry to rerun this test as root.\n");
87		} else {
88			perror("An error occurs when calling seteuid()");
89		}
90		shm_unlink(SHM_NAME);
91		return PTS_UNRESOLVED;
92	}
93
94	printf("Testing with user '%s' (uid: %i)\n", pw->pw_name, pw->pw_uid);
95
96	fd = shm_open(SHM_NAME, O_RDWR | O_TRUNC, 0);
97	if (fd == -1) {
98		perror("An error occurs when calling shm_open()");
99		seteuid(getuid());
100		shm_unlink(SHM_NAME);
101		return PTS_UNRESOLVED;
102	}
103
104	if (fstat(fd, &stat_buf) != 0) {
105		perror("An error occurs when calling fstat()");
106		seteuid(getuid());
107		shm_unlink(SHM_NAME);
108		return PTS_UNRESOLVED;
109	}
110
111	seteuid(getuid());
112	shm_unlink(SHM_NAME);
113
114	if (stat_buf.st_uid == old_uid && stat_buf.st_gid == old_gid) {
115		printf("Test PASSED\n");
116		return PTS_PASS;
117	}
118
119	if (stat_buf.st_uid != old_uid)
120		printf("The user ID has changed.\n");
121	if (stat_buf.st_gid != old_gid)
122		printf("The group ID has changed.\n");
123	return PTS_FAIL;
124}
125