source: trunk/src/sh_sem.c

Last change on this file was 522, checked in by katerina, 5 years ago

Fix for ticket #417 (bus error on Solaris/SPARC).

File size: 7.3 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
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#if !defined(HAVE_UNION_SEMUN)
52/* according to X/OPEN we have to define it ourselves */
53union semun {
54  int val;
55  struct semid_ds *buf;
56  unsigned short *array;
57};
58#endif
59#endif
60
61
62#define SH_SEMVMX 32767
63
64static int get_semaphore (void) 
65{
66  key_t  key = ftok(DEFAULT_DATAROOT, '#');
67  int    semid;
68
69  if (key < 0)
70    return -1;
71  semid = semget (key, 0, IPC_PRIVATE);
72  if (semid < 0)
73    return -1;
74  return semid;
75}
76
77static void sem_purge(int sem_id)
78{
79  union semun tmp;
80
81  tmp.val = 0;
82 
83  if (sem_id != -1)
84    semctl(sem_id, 0, IPC_RMID, tmp);
85  return;
86}
87
88static void sem_purge_stale()
89{
90  int stale_ID = get_semaphore();
91  if (stale_ID != -1)
92    sem_purge(stale_ID);
93  return;
94}
95
96static int report_err(int errnum, char * file, int line, char * func)
97{
98  char errbuf[SH_ERRBUF_SIZE];
99  sh_error_message(errnum, errbuf, sizeof(errbuf));
100  sh_error_handle((-1), file, line, errnum, MSG_E_SUBGEN,
101                  errbuf, func);
102  return -1;
103}
104
105static int init_semaphore (int nsems) 
106{
107  int    i;
108  mode_t mask;
109  int    semid;
110  int    errnum;
111  union semun tmp;
112  key_t  key = ftok(DEFAULT_DATAROOT, '#');
113
114  if (key < 0)
115    return report_err(errno, FIL__, __LINE__, _("ftok"));
116
117  mask   = umask(0);
118  semid  = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0660);
119  errnum = errno;
120  umask(mask);
121 
122  tmp.val = 1;
123
124  if (semid < 0)
125    return report_err(errnum, FIL__, __LINE__, _("semget"));
126  for (i=0; i<nsems; ++i)
127    if (semctl (semid, i, SETVAL, tmp) == -1)
128      return report_err(errnum, FIL__, __LINE__, _("semclt"));
129  return semid;
130}
131
132
133static int sem_set(int semid, int sem_no, int val)
134{
135  union semun tmp;
136
137  tmp.val = val;
138 
139  if (semid < 0)
140    return -1;
141  if (semctl (semid, sem_no, SETVAL, tmp) == -1)
142    return -1;
143  return 0;
144}
145
146static int sem_get(int semid, int sem_no)
147{
148  union semun tmp;
149  if (semid < 0)
150    return -1;
151  tmp.val = 0;
152  return semctl (semid, sem_no, GETVAL, tmp);
153}
154
155
156static int sem_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 = 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
171static int sem_try_change(int semid, int sem_no, int amount)
172{
173  struct sembuf tmp;
174  int retval;
175
176  tmp.sem_num = sem_no;
177  tmp.sem_flg = IPC_NOWAIT|SEM_UNDO;
178  tmp.sem_op  = amount;
179
180  do { retval = semop(semid, &tmp, 1);
181  } while (retval == -1 && errno == EINTR);
182
183  return retval;
184}
185
186#define SH_SEMAPHORE_EXTERN(S)  int S = get_semaphore()
187#define SH_SEMAPHORE_INIT(S, N) int S = init_semaphore(N)
188#define SH_SEMAPHORE_TRYLOCK(S) sem_try_change(S, 0, SH_SEM_LOCK)
189#define SH_SEMAPHORE_LOCK(S)    sem_change(S, 0, SH_SEM_LOCK)
190#define SH_SEMAPHORE_UNLOCK(S)  sem_change(S, 0, SH_SEM_UNLOCK)
191#define SH_SEMAPHORE_PURGE(S)   sem_purge(S)
192
193static int sem_ID = -1;
194
195void sh_sem_open()
196{
197  if (sh.flag.isdaemon != S_TRUE)
198    return;
199
200  if (sem_ID < 0)
201    {
202      sem_purge_stale();
203      sem_ID = init_semaphore(2);
204      sem_set(sem_ID, 1, (int) 0);
205    }
206
207  return;
208}
209
210void sh_sem_trylock()
211{
212  SH_SEMAPHORE_TRYLOCK(sem_ID);
213  return;
214}
215
216void sh_sem_lock()
217{
218  SH_SEMAPHORE_LOCK(sem_ID);
219  return;
220}
221
222void sh_sem_unlock (long val)
223{
224  if (val >= 0)
225    {
226      val = (val > SH_SEMVMX) ? SH_SEMVMX : val; /* signed short int maxval */
227      sem_set(sem_ID, 1, (int) val);
228    }
229  SH_SEMAPHORE_UNLOCK(sem_ID);
230  return;
231}
232
233void sh_sem_close()
234{
235  SH_SEMAPHORE_PURGE(sem_ID);
236  return;
237}
238
239static volatile int alarm_triggered = 0;
240static void alarm_handler(int sig)
241{
242  (void) sig;
243  alarm_triggered = 1;
244  return;
245}
246
247int  sh_sem_wait(const char * wait)
248{
249  int rc, flag = 0;
250  int time_wait = atoi(wait);
251
252  SH_SEMAPHORE_EXTERN(sem_id);
253
254  if (time_wait < 0) { time_wait *= (-1); time_wait -= 1; flag = 1; }
255  if (time_wait < 0 || time_wait > (24*3600))
256    {
257      fprintf(stderr, _("Invalid argument <%d>.\n"), time_wait);
258      _exit(exit_err);
259    }
260  if (sem_id == -1)
261    {
262      if (flag && errno == ENOENT) { 
263        do { retry_msleep(1, 0); rc = get_semaphore(); } while (rc == -1);
264        sem_id = rc;
265      } else {
266        if (errno == ENOENT) {
267          fputs(_("Samhain IPC not initialized.\n"), stderr);
268          _exit(exit_err); }
269        else if (errno == EACCES)
270          fputs(_("No permission to access Samhain IPC.\n"), stderr);
271        _exit(exit_err);
272      }
273    }
274
275  retry_msleep(0, 50);
276
277  if (time_wait > 0)
278    {
279      signal(SIGALRM, alarm_handler);
280      alarm(time_wait);
281    }
282  rc = SH_SEMAPHORE_LOCK(sem_id);
283  if (rc == -1 && errno == EINTR)
284    {
285      if (alarm_triggered)
286        {
287          fputs(_("Timeout on wait.\n"), stderr);
288          _exit(exit_time);
289        }
290    }
291  else if (rc == -1)
292    {
293      if (errno == EACCES)
294        fputs(_("No permission to access Samhain IPC.\n"), stderr);
295      else
296        perror(_("semop"));
297      _exit(exit_err);
298    }
299
300  rc = sem_get(sem_id, 1);
301  if (rc == 0)   
302    _exit(exit_ok);
303  else if (rc == SH_SEMVMX)
304    fprintf(stdout, _("%d or more issues reported\n"), rc);
305  else
306    fprintf(stdout, _("%d issues reported\n"), rc);
307  _exit(exit_fail);
308}
309
310#else
311
312void sh_sem_open()    { return; }
313void sh_sem_trylock() { return; }
314void sh_sem_lock()    { return; }
315void sh_sem_unlock(long val)  { (void) val; return; }
316void sh_sem_close()   { return; }
317int  sh_sem_wait(const char * wait)
318{
319  (void) wait;
320  fputs(_("Function not implemented (OS does not support SysV semaphores).\n"),
321        stderr);
322  exit(exit_err);
323}
324
325#endif /* defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H) */
Note: See TracBrowser for help on using the repository browser.