source: trunk/src/sh_sub.c @ 323

Last change on this file since 323 was 323, checked in by katerina, 11 years ago

Fix for ticket #242 (Compile error on FreeBSD) and #241 (deploy.sh documentation)

File size: 10.7 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2011 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
22/* 0->1 for debug */ 
23#if 0
24#define SH_SUB_DBG 1
25#endif
26
27#ifndef NULL
28#if !defined(__cplusplus)
29#define NULL ((void*)0)
30#else
31#define NULL (0)
32#endif
33#endif
34
35
36#include <stdio.h>
37#include <string.h>
38#include <errno.h>
39#include <limits.h>
40
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <sys/wait.h>
44#include <unistd.h>
45#include <fcntl.h>
46#include <poll.h>
47
48#include "samhain.h"
49#include "sh_pthread.h"
50
51#ifndef HAVE_LSTAT
52#define lstat stat
53#endif
54
55#define FIL__ _("sh_sub.c")
56
57static pid_t sh_child_pid = -1;
58static pid_t sh_wait_ret  =  1;
59
60static int parent2child[2];
61static int child2parent[2];
62
63SH_MUTEX_STATIC(mutex_sub,      PTHREAD_MUTEX_INITIALIZER);
64SH_MUTEX_STATIC(mutex_sub_work, PTHREAD_MUTEX_INITIALIZER);
65
66static void wait_for_command();
67static ssize_t sh_sub_read(int fd, void *buf, size_t count);
68
69void sh_kill_sub()
70{
71  SH_MUTEX_LOCK(mutex_sub);
72
73  if (sh_child_pid != -1)
74    {
75      int status;
76#ifdef WCONTINUED
77      int wflags = WNOHANG|WUNTRACED|WCONTINUED;
78#else
79      int wflags = WNOHANG|WUNTRACED;
80#endif
81
82      close (parent2child[1]);
83      close (child2parent[0]);
84
85      /* fprintf(stderr, "FIXME kill_sub %d\n", (int) sh_child_pid); */
86
87      /* Let's be rude. */
88      kill(sh_child_pid, SIGKILL);
89
90      retry_msleep(1,0);
91
92      if (sh_wait_ret == 0)
93        sh_wait_ret = waitpid(          -1, &status, wflags);
94      else
95        sh_wait_ret = waitpid(sh_child_pid, &status, wflags);
96
97      sh_child_pid = -1;
98    }
99
100  SH_MUTEX_UNLOCK(mutex_sub);
101  return;
102}
103
104static int sh_create_sub()
105{
106  pid_t res;
107  volatile int   retval = 0;
108
109  SH_MUTEX_LOCK(mutex_sub);
110
111#if !defined(O_NONBLOCK)
112#if defined(O_NDELAY)
113#define O_NONBLOCK  O_NDELAY
114#else
115#define O_NONBLOCK  0
116#endif
117#endif
118
119  if (sh_child_pid == -1)
120    {
121      sigset_t signal_set_new;
122      sigset_t signal_set_old;
123
124      sigfillset ( &signal_set_new );
125      sigemptyset( &signal_set_old );
126
127      /* Create pipes. */
128      res = pipe (parent2child);
129      if (res == 0)
130        res = pipe (child2parent);
131     
132      if (res != 0)
133        goto out;
134
135      SH_SETSIGMASK(SIG_BLOCK, &signal_set_new, &signal_set_old);
136
137      res = fork();
138     
139      if (res == 0)
140        {
141          /* Child process. */
142#ifdef _SC_OPEN_MAX
143          int fdlimit = sysconf (_SC_OPEN_MAX);
144#else
145#ifdef OPEN_MAX
146          int fdlimit = OPEN_MAX;
147#else
148          int fdlimit = _POSIX_OPEN_MAX;
149#endif
150#endif
151          int sflags, i, fd = 0;
152          struct sigaction act;
153
154          /* zero private information
155           */
156          memset(skey, 0, sizeof(sh_key_t)); 
157
158          close (parent2child[1]);
159          close (child2parent[0]);
160         
161          sflags = fcntl(parent2child[0], F_GETFL, 0);
162          fcntl(parent2child[0], F_SETFL, sflags | O_NONBLOCK);
163          sflags = fcntl(child2parent[1], F_GETFL, 0);
164          fcntl(child2parent[1], F_SETFL, sflags | O_NONBLOCK);
165
166          /* close inherited file descriptors
167           */
168          if (fdlimit < 0) 
169            fdlimit = 20;  /* POSIX lower limit */
170          while (fd < fdlimit)
171            {
172              if (fd != parent2child[0] && fd != child2parent[1])
173                close(fd);
174              ++fd;
175            }
176
177          /*
178          for (i = 0; i < 3; ++i)
179            {
180              if ( fcntl(i, F_GETFL, 0) == (-1))
181                (void) open(_("/dev/null"), O_RDWR, 0);
182            }
183          */
184
185          /* reset signal handling
186           */
187          act.sa_handler = SIG_DFL;
188          for (i = 0; i < NSIG; ++i)
189            sigaction(i, &act, NULL);
190          SH_SETSIGMASK(SIG_UNBLOCK, &signal_set_new, NULL);
191
192          wait_for_command();
193         
194          _exit(0);
195        }
196      else if (res > 0)
197        {
198          /* Parent process. */
199          int sflags;
200
201          SH_SETSIGMASK(SIG_SETMASK, &signal_set_old, NULL);
202
203          close (parent2child[0]);
204          close (child2parent[1]);
205         
206          sflags = fcntl(parent2child[1], F_GETFL, 0);
207          fcntl(parent2child[1], F_SETFL, sflags | O_NONBLOCK);
208          sflags = fcntl(child2parent[0], F_GETFL, 0);
209          fcntl(child2parent[0], F_SETFL, sflags | O_NONBLOCK);
210
211          sh_child_pid = res;
212
213          /* fprintf(stderr, "FIXME create_sub %d\n", (int) sh_child_pid); */
214        }
215      else
216        {
217          /* Failure. */
218
219          SH_SETSIGMASK(SIG_SETMASK, &signal_set_old, NULL);
220
221          close (parent2child[0]);
222          close (parent2child[1]);
223
224          close (child2parent[0]);
225          close (child2parent[1]);
226         
227          retval = -1;
228        }
229    }
230
231 out:
232  ; /* 'label at end of compound statement' */
233  SH_MUTEX_UNLOCK(mutex_sub);
234  return retval;
235}
236
237#define  SH_SUB_BUF (PIPE_BUF-1)
238struct sh_sub_in {
239  char   command;
240  char   path[SH_SUB_BUF];
241};
242
243struct sh_sub_out {
244  int retval;
245  int errnum;
246  struct stat sbuf;
247};
248
249#define SH_COM_STAT  0
250#define SH_COM_LSTAT 1
251
252static ssize_t sh_sub_write(int fd, const void *buf, size_t count)
253{
254  ssize_t rcount;
255  int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
256  int tti = 1; 
257
258  do {
259
260    rcount = write(fd, buf, count);
261    if (rcount > 0) 
262      {
263        count -= rcount; buf += rcount; --ttl;
264      }
265
266    if (count > 0)
267      {
268        if (ttl > 0)
269          {
270            retry_msleep(0, tti);
271            tti *= 9;
272          }
273        else
274          {
275            return -1;
276          }
277      }
278  } while (count > 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
279
280  if (count > 0)
281    return -1;
282  return 0;
283}
284
285static void wait_for_command()
286{
287  int               ret;
288  struct pollfd     fds;
289  struct sh_sub_in  inbuf;
290  struct sh_sub_out outbuf;
291
292  fds.fd     = parent2child[0];
293  fds.events = POLLIN;
294
295  do {
296
297    /* fprintf(stderr, "FIXME wait_com polling..\n"); */
298
299    do {
300      ret = poll(&fds, 1, -1);
301    } while (ret < 0 && errno == EINTR);
302
303    if (ret > 0)
304      {
305        ret = sh_sub_read(parent2child[0], &inbuf, sizeof(inbuf));
306
307        /*
308        fprintf(stderr, "FIXME wait_com stat %s (%s)\n",
309                inbuf.path, (inbuf.command == SH_COM_LSTAT) ? "lstat" : "stat");
310        */
311
312        if (ret == 0)
313          {
314            if (inbuf.command == SH_COM_LSTAT)
315              {
316                do { 
317                  outbuf.retval = lstat(inbuf.path, &(outbuf.sbuf)); 
318                } while (outbuf.retval < 0 && errno == EAGAIN);
319              }
320            else
321              {
322                do { 
323                  outbuf.retval = stat(inbuf.path, &(outbuf.sbuf)); 
324                } while (outbuf.retval < 0 && errno == EAGAIN);
325              }
326
327            outbuf.errnum = errno;
328
329            /* fprintf(stderr, "FIXME wait_com writing..\n"); */
330
331            ret = sh_sub_write(child2parent[1], &outbuf, sizeof(outbuf));
332            if (ret < 0)
333              {
334                /* fprintf(stderr, "FIXME wait_com return 1\n"); */
335                return;
336              }
337          }
338        else /* sh_sub_read() < 0 */
339          {
340            /* fprintf(stderr, "FIXME wait_com return 2\n"); */
341            return;
342          }
343      }
344   
345    /* fprintf(stderr, "FIXME wait_com next..\n"); */
346
347  } while (1 == 1);
348}
349
350static ssize_t sh_sub_read(int fd, void *buf, size_t count)
351{
352  ssize_t rcount;
353  int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
354  int tti = 1; 
355
356  do {
357    rcount = read(fd, buf, count);
358
359    if (rcount > 0) 
360      {
361        count -= rcount; buf += rcount; --ttl;
362      }
363
364    if (count > 0)
365      {
366        if (ttl > 0)
367          {
368            retry_msleep(0, tti);
369            tti *= 9;
370          }
371        else
372          {
373            return -1;
374          }
375      }
376  } while (count > 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
377
378  if (count > 0)
379    return -1;
380
381  return 0;
382}
383
384#ifdef SH_SUB_DBG
385#include <stdarg.h>
386static void debug_it (const char *fmt, ...)
387{
388  char msg[256];
389  va_list ap;
390
391  int fd = open("debug.it", O_CREAT|O_WRONLY|O_APPEND, 0666);
392
393  va_start(ap, fmt);
394  vsnprintf(msg, sizeof(msg), fmt, ap);  /* flawfinder: ignore */
395  va_end(ap);
396
397  write(fd, msg, strlen(msg));
398  write(fd, "\n", 1);
399  close(fd);
400  return;
401}
402#endif
403
404static int sh_sub_stat_int(const char *path, struct stat *buf, char command)
405{
406  int retval;
407  volatile int sflag = 0;
408  struct sh_sub_in  inbuf;
409  struct sh_sub_out outbuf;
410  struct pollfd     pfds;
411
412  size_t len = strlen(path) + 1;
413
414  if (len > SH_SUB_BUF)
415    {
416      if (command == SH_COM_LSTAT)
417        {
418          do { 
419            retval = lstat(path, buf); 
420          } while (retval < 0 && errno == EAGAIN);
421
422          return retval;
423        }
424      else
425        {
426          do { 
427            retval = stat(path, buf); 
428          } while (retval < 0 && errno == EAGAIN);
429
430          return retval;
431        }
432    }
433
434  sl_strlcpy(inbuf.path, path, SH_SUB_BUF);
435  inbuf.command = command;
436
437 start:
438
439#ifdef SH_SUB_DBG
440  debug_it("%d sh_child_pid %d\n", (int)getpid(), (int) sh_child_pid);
441#endif
442
443  if (sh_child_pid == -1)
444    sh_create_sub();
445
446#ifdef SH_SUB_DBG
447  debug_it("%d stat_sub %s (%d)\n", (int)getpid(), inbuf.path, (int) sh_child_pid);
448#endif
449
450  SH_MUTEX_LOCK(mutex_sub_work);
451
452  retval = sh_sub_write(parent2child[1], &inbuf, sizeof(inbuf));
453  if (retval < 0)
454    {
455      sh_kill_sub();
456      sflag = 1;
457      goto end;
458    }
459
460#ifdef SH_SUB_DBG
461  debug_it("%d stat_sub polling..\n", (int)getpid());
462#endif
463
464  pfds.fd     = child2parent[0];
465  pfds.events = POLLIN;
466
467  do {
468    retval = poll(&pfds, 1, 1000);
469  } while (retval < 0 && errno == EINTR);
470
471  if (retval <= 0)
472    {
473      sh_kill_sub();
474      sflag = -1;
475      goto end;
476    }
477
478#ifdef SH_SUB_DBG
479  debug_it("%d stat_sub reading..\n", (int)getpid());
480#endif
481
482  retval = sh_sub_read (child2parent[0], &outbuf, sizeof(outbuf));
483  if (retval < 0)
484    {
485      sh_kill_sub();
486      sflag = 1;
487      goto end;
488    }
489
490 end:
491  ; /* 'label at end of compound statement' */
492  SH_MUTEX_UNLOCK(mutex_sub_work);
493
494  if      (sflag == 0)
495    {
496#ifdef SH_SUB_DBG
497      debug_it("%d stat_sub done..\n", (int)getpid());
498#endif
499      memcpy(buf, &(outbuf.sbuf), sizeof(struct stat));
500      errno = outbuf.errnum;
501      return outbuf.retval;
502    }
503  else if (sflag == 1)
504    {
505#ifdef SH_SUB_DBG
506      debug_it("%d stat_sub error..\n", (int)getpid());
507#endif
508      /* could not read, thus subprocess may have gone */
509      sflag = 0;
510      goto start;
511    }
512
513  return -1;
514}
515
516int sh_sub_stat (const char *path, struct stat *buf)
517{
518  return sh_sub_stat_int(path, buf, SH_COM_STAT);
519}
520
521int sh_sub_lstat(const char *path, struct stat *buf)
522{
523  return sh_sub_stat_int(path, buf, SH_COM_LSTAT);
524}
525
Note: See TracBrowser for help on using the repository browser.