source: trunk/src/sh_sem.c@ 494

Last change on this file since 494 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 7.2 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000, 2015 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21#include <stdlib.h>
22#include <stdio.h>
23
24#if defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H)
25#include "samhain.h"
26#include "sh_sem.h"
27#include "sh_error_min.h"
28
29#include <signal.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/ipc.h>
33#include <sys/sem.h>
34#include <unistd.h>
35
36#undef FIL__
37#define FIL__ _("sh_sem.c")
38
39typedef enum {
40 exit_ok = 0,
41 exit_fail = 1,
42 exit_time = 2,
43 exit_err = 3
44} sh_estat;
45
46#if 0
47/* FreeBSD 6.1 defines this in <sys/sem.h> too... */
48#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
49/* union semun is defined by including <sys/sem.h> */
50#else
51/* according to X/OPEN we have to define it ourselves */
52union semun {
53 int val;
54 struct semid_ds *buf;
55 unsigned short *array;
56};
57#endif
58#endif
59
60#define SH_SEMVMX 32767
61
62static int get_semaphore (void)
63{
64 key_t key = ftok(DEFAULT_DATAROOT, '#');
65 int semid;
66
67 if (key < 0)
68 return -1;
69 semid = semget (key, 0, IPC_PRIVATE);
70 if (semid < 0)
71 return -1;
72 return semid;
73}
74
75static void sem_purge(int sem_id)
76{
77 if (sem_id != -1)
78 semctl(sem_id, 0, IPC_RMID, (int)0);
79 return;
80}
81
82static void sem_purge_stale()
83{
84 int stale_ID = get_semaphore();
85 if (stale_ID != -1)
86 sem_purge(stale_ID);
87 return;
88}
89
90static int report_err(int errnum, char * file, int line, char * func)
91{
92 char errbuf[SH_ERRBUF_SIZE];
93 sh_error_message(errnum, errbuf, sizeof(errbuf));
94 sh_error_handle((-1), file, line, errnum, MSG_E_SUBGEN,
95 errbuf, func);
96 return -1;
97}
98
99static int init_semaphore (int nsems)
100{
101 int i;
102 mode_t mask;
103 int semid;
104 int errnum;
105 key_t key = ftok(DEFAULT_DATAROOT, '#');
106
107 if (key < 0)
108 return report_err(errno, FIL__, __LINE__, _("ftok"));
109
110 mask = umask(0);
111 semid = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0660);
112 errnum = errno;
113 umask(mask);
114
115 if (semid < 0)
116 return report_err(errnum, FIL__, __LINE__, _("semget"));
117 for (i=0; i<nsems; ++i)
118 if (semctl (semid, i, SETVAL, (int) 1) == -1)
119 return report_err(errnum, FIL__, __LINE__, _("semclt"));
120 return semid;
121}
122
123
124static int sem_set(int semid, int sem_no, int val)
125{
126 if (semid < 0)
127 return -1;
128 if (semctl (semid, sem_no, SETVAL, val) == -1)
129 return -1;
130 return 0;
131}
132
133static int sem_get(int semid, int sem_no)
134{
135 if (semid < 0)
136 return -1;
137 return semctl (semid, sem_no, GETVAL, (int) 0);
138}
139
140
141static int sem_change(int semid, int sem_no, int amount)
142{
143 struct sembuf tmp;
144 int retval;
145
146 tmp.sem_num = sem_no;
147 tmp.sem_flg = SEM_UNDO;
148 tmp.sem_op = amount;
149
150 do { retval = semop(semid, &tmp, 1);
151 } while (retval == -1 && errno == EINTR);
152
153 return retval;
154}
155
156static int sem_try_change(int semid, int sem_no, int amount)
157{
158 struct sembuf tmp;
159 int retval;
160
161 tmp.sem_num = sem_no;
162 tmp.sem_flg = IPC_NOWAIT|SEM_UNDO;
163 tmp.sem_op = amount;
164
165 do { retval = semop(semid, &tmp, 1);
166 } while (retval == -1 && errno == EINTR);
167
168 return retval;
169}
170
171#define SH_SEMAPHORE_EXTERN(S) int S = get_semaphore()
172#define SH_SEMAPHORE_INIT(S, N) int S = init_semaphore(N)
173#define SH_SEMAPHORE_TRYLOCK(S) sem_try_change(S, 0, SH_SEM_LOCK)
174#define SH_SEMAPHORE_LOCK(S) sem_change(S, 0, SH_SEM_LOCK)
175#define SH_SEMAPHORE_UNLOCK(S) sem_change(S, 0, SH_SEM_UNLOCK)
176#define SH_SEMAPHORE_PURGE(S) sem_purge(S)
177
178static int sem_ID = -1;
179
180void sh_sem_open()
181{
182 if (sh.flag.isdaemon != S_TRUE)
183 return;
184
185 if (sem_ID < 0)
186 {
187 sem_purge_stale();
188 sem_ID = init_semaphore(2);
189 sem_set(sem_ID, 1, (int) 0);
190 }
191
192 return;
193}
194
195void sh_sem_trylock()
196{
197 SH_SEMAPHORE_TRYLOCK(sem_ID);
198 return;
199}
200
201void sh_sem_lock()
202{
203 SH_SEMAPHORE_LOCK(sem_ID);
204 return;
205}
206
207void sh_sem_unlock (long val)
208{
209 if (val >= 0)
210 {
211 val = (val > SH_SEMVMX) ? SH_SEMVMX : val; /* signed short int maxval */
212 sem_set(sem_ID, 1, (int) val);
213 }
214 SH_SEMAPHORE_UNLOCK(sem_ID);
215 return;
216}
217
218void sh_sem_close()
219{
220 SH_SEMAPHORE_PURGE(sem_ID);
221 return;
222}
223
224static volatile int alarm_triggered = 0;
225static void alarm_handler(int sig)
226{
227 (void) sig;
228 alarm_triggered = 1;
229 return;
230}
231
232int sh_sem_wait(const char * wait)
233{
234 int rc, flag = 0;
235 int time_wait = atoi(wait);
236
237 SH_SEMAPHORE_EXTERN(sem_id);
238
239 if (time_wait < 0) { time_wait *= (-1); time_wait -= 1; flag = 1; }
240 if (time_wait < 0 || time_wait > (24*3600))
241 {
242 fprintf(stderr, _("Invalid argument <%d>.\n"), time_wait);
243 _exit(exit_err);
244 }
245 if (sem_id == -1)
246 {
247 if (flag && errno == ENOENT) {
248 do { retry_msleep(1, 0); rc = get_semaphore(); } while (rc == -1);
249 sem_id = rc;
250 } else {
251 if (errno == ENOENT) {
252 fputs(_("Samhain IPC not initialized.\n"), stderr);
253 _exit(exit_err); }
254 else if (errno == EACCES)
255 fputs(_("No permission to access Samhain IPC.\n"), stderr);
256 _exit(exit_err);
257 }
258 }
259
260 retry_msleep(0, 50);
261
262 if (time_wait > 0)
263 {
264 signal(SIGALRM, alarm_handler);
265 alarm(time_wait);
266 }
267 rc = SH_SEMAPHORE_LOCK(sem_id);
268 if (rc == -1 && errno == EINTR)
269 {
270 if (alarm_triggered)
271 {
272 fputs(_("Timeout on wait.\n"), stderr);
273 _exit(exit_time);
274 }
275 }
276 else if (rc == -1)
277 {
278 if (errno == EACCES)
279 fputs(_("No permission to access Samhain IPC.\n"), stderr);
280 else
281 perror(_("semop"));
282 _exit(exit_err);
283 }
284
285 rc = sem_get(sem_id, 1);
286 if (rc == 0)
287 _exit(exit_ok);
288 else if (rc == SH_SEMVMX)
289 fprintf(stdout, _("%d or more issues reported\n"), rc);
290 else
291 fprintf(stdout, _("%d issues reported\n"), rc);
292 _exit(exit_fail);
293}
294
295#else
296
297void sh_sem_open() { return; }
298void sh_sem_trylock() { return; }
299void sh_sem_lock() { return; }
300void sh_sem_unlock(long val) { (void) val; return; }
301void sh_sem_close() { return; }
302int sh_sem_wait(const char * wait)
303{
304 (void) wait;
305 fputs(_("Function not implemented (OS does not support SysV semaphores).\n"),
306 stderr);
307 exit(exit_err);
308}
309
310#endif /* defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H) */
Note: See TracBrowser for help on using the repository browser.