source: trunk/src/sh_sem.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 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.