Home | History | Annotate | Download | only in sem_unlink
      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)  */
     95 int 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. */
    130 int 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