3-1.c revision 4ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87
1/*
2* Copyright (c) 2005, Bull S.A..  All rights reserved.
3* Created by: Sebastien Decugis
4
5* This program is free software; you can redistribute it and/or modify it
6* under the terms of version 2 of the GNU General Public License as
7* published by the Free Software Foundation.
8*
9* This program is distributed in the hope that it would be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program; if not, write the Free Software Foundation, Inc.,
15* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17* This sample test aims to check the following assertion:
18*
19*  sem_unlink will return -1 and set errno to EACCESS if the process has not
20* priviledge to unlink the sem.
21
22* The steps are:
23* -> open a semaphore with 0744 mask
24* -> fork
25* -> change child uid
26* -> child attempts to unlink the semaphore. It should fail.
27* -> join the child
28* -> sem_unlink (should be OK)
29
30* The test fails if the child process is able to unlink the semaphore.
31
32*/
33
34/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
35#define _POSIX_C_SOURCE 200112L
36
37/* Some of the routines are XSI extensions */
38#define _XOPEN_SOURCE 600
39
40/******************************************************************************/
41/*************************** standard includes ********************************/
42/******************************************************************************/
43#include <pthread.h>
44#include <stdarg.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include <pwd.h>
51#include <semaphore.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <sys/wait.h>
55
56/******************************************************************************/
57/***************************   Test framework   *******************************/
58/******************************************************************************/
59#include "../testfrmw/testfrmw.h"
60#include "../testfrmw/testfrmw.c"
61/* This header is responsible for defining the following macros:
62 * UNRESOLVED(ret, descr);
63 *    where descr is a description of the error and ret is an int
64 *   (error code for example)
65 * FAILED(descr);
66 *    where descr is a short text saying why the test has failed.
67 * PASSED();
68 *    No parameter.
69 *
70 * Both three macros shall terminate the calling process.
71 * The testcase shall not terminate in any other maneer.
72 *
73 * The other file defines the functions
74 * void output_init()
75 * void output(char * string, ...)
76 *
77 * Those may be used to output information.
78 */
79
80/******************************************************************************/
81/**************************** Configuration ***********************************/
82/******************************************************************************/
83#ifndef VERBOSE
84#define VERBOSE 1
85#endif
86
87#define SEM_NAME  "/sem_unlink_3_1"
88
89/******************************************************************************/
90/***************************    Test case   ***********************************/
91/******************************************************************************/
92
93/* Set the euid of this process to a non-root uid */
94/* (from ../sem_open/3-1.c)  */
95int set_nonroot()
96{
97
98	struct passwd *pw;
99	setpwent();
100	/* search for the first user which is non root */
101
102	while ((pw = getpwent()) != NULL)
103		if (strcmp(pw->pw_name, "root"))
104			break;
105
106	endpwent();
107
108	if (pw == NULL) {
109		output("There is no other user than current and root.\n");
110		return 1;
111	}
112
113	if (seteuid(pw->pw_uid) != 0) {
114		if (errno == EPERM) {
115			output
116			    ("You don't have permission to change your UID.\n");
117			return 1;
118		}
119
120		perror("An error occurs when calling seteuid()");
121		return 1;
122	}
123
124	output("Testing with user '%s' (uid: %d)\n",
125	       pw->pw_name, (int)geteuid());
126	return 0;
127}
128
129/* The main test function. */
130int main(void)
131{
132	int ret, status;
133	pid_t ch, ctl;
134	sem_t *sem;
135
136	/* Initialize output */
137	output_init();
138
139	/* Create the semaphore */
140	sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0744, 1);
141
142	if ((sem == SEM_FAILED) && (errno == EEXIST)) {
143		sem_unlink(SEM_NAME);
144		sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0744, 1);
145	}
146
147	if (sem == SEM_FAILED) {
148		UNRESOLVED(errno, "Failed to create the semaphore");
149	}
150
151	/* fork */
152	ch = fork();
153
154	if (ch == -1) {
155		UNRESOLVED(errno, "Failed to fork");
156	}
157
158	if (ch == 0) {		/* child */
159		/* connect to the semaphore */
160		sem = sem_open(SEM_NAME, 0);
161
162		if (sem == SEM_FAILED) {
163			output
164			    ("Failed to connect to the semaphore, error %d: %s\n",
165			     errno, strerror(errno));
166			exit(1);
167		}
168
169		/* change euid */
170		ret = set_nonroot();
171
172		if (ret) {
173			output("Changing euid failed\n");
174			exit(1);
175		}
176
177		/* try and unlink, it should fail */
178		ret = sem_unlink(SEM_NAME);
179
180		if (ret == 0) {
181			output("sem_unlink did not fail in child");
182			exit(2);
183		}
184
185		if (errno != EACCES) {
186			output
187			    ("sem_unlink failed with unexpected error %d: %s\n",
188			     errno, strerror(errno));
189			exit(2);
190		}
191
192		/* Ok, child is done. */
193		exit(0);
194	}
195
196	/* Parent waits for the child to finish */
197	ctl = waitpid(ch, &status, 0);
198
199	if (ctl != ch) {
200		UNRESOLVED(errno, "Waitpid returned the wrong PID");
201	}
202
203	if (!WIFEXITED(status)) {
204		FAILED("Child exited abnormally");
205	}
206
207	if (WEXITSTATUS(status) == 1) {
208		UNRESOLVED(0, "An error occured in child");
209	}
210
211	if (WEXITSTATUS(status) == 2) {
212		FAILED("Test failed in child");
213	}
214
215	if (WEXITSTATUS(status) != 0) {
216		UNRESOLVED(0, "Unexpected return value from child");
217	}
218
219	/* Unlink */
220	ret = sem_unlink(SEM_NAME);
221
222	if (ret != 0) {
223		UNRESOLVED(errno, "Failed to unlink the semaphore");
224	}
225
226	/* Test passed */
227#if VERBOSE > 0
228	output("Test passed\n");
229
230#endif
231	PASSED;
232}
233