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