source: trunk/src/sh_sub.c @ 429

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

Fix for ticket #336 (compile error on HP-UX)

File size: 11.0 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  char * mbuf = (char *) buf;
255  ssize_t rcount;
256  int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
257  int tti = 1; 
258
259  do {
260
261    rcount = write(fd, mbuf, count);
262    if (rcount > 0) 
263      {
264        count -= rcount; mbuf += rcount; --ttl;
265      }
266
267    if (count > 0)
268      {
269        if (ttl > 0)
270          {
271            retry_msleep(0, tti);
272            tti *= 9;
273          }
274        else
275          {
276            return -1;
277          }
278      }
279  } while (count > 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
280
281  if (count > 0)
282    return -1;
283  return 0;
284}
285
286static void wait_for_command()
287{
288  int               ret;
289  struct pollfd     fds;
290  struct sh_sub_in  inbuf;
291  struct sh_sub_out outbuf;
292
293  fds.fd     = parent2child[0];
294  fds.events = POLLIN;
295
296  do {
297
298    /* fprintf(stderr, "FIXME wait_com polling..\n"); */
299
300    do {
301      ret = poll(&fds, 1, -1);
302    } while (ret < 0 && errno == EINTR);
303
304    if (ret > 0)
305      {
306        ret = sh_sub_read(parent2child[0], &inbuf, sizeof(inbuf));
307
308        /*
309        fprintf(stderr, "FIXME wait_com stat %s (%s)\n",
310                inbuf.path, (inbuf.command == SH_COM_LSTAT) ? "lstat" : "stat");
311        */
312
313        if (ret == 0)
314          {
315            if (inbuf.command == SH_COM_LSTAT)
316              {
317                do { 
318                  outbuf.retval = lstat(inbuf.path, &(outbuf.sbuf)); 
319                } while (outbuf.retval < 0 && errno == EAGAIN);
320              }
321            else
322              {
323                do { 
324                  outbuf.retval = stat(inbuf.path, &(outbuf.sbuf)); 
325                } while (outbuf.retval < 0 && errno == EAGAIN);
326              }
327
328            outbuf.errnum = errno;
329
330            /* fprintf(stderr, "FIXME wait_com writing..\n"); */
331
332            ret = sh_sub_write(child2parent[1], &outbuf, sizeof(outbuf));
333            if (ret < 0)
334              {
335                /* fprintf(stderr, "FIXME wait_com return 1\n"); */
336                return;
337              }
338          }
339        else /* sh_sub_read() < 0 */
340          {
341            /* fprintf(stderr, "FIXME wait_com return 2\n"); */
342            return;
343          }
344      }
345   
346    /* fprintf(stderr, "FIXME wait_com next..\n"); */
347
348  } while (1 == 1);
349}
350
351#ifndef ETIMEDOUT
352#define ETIMEDOUT EIO
353#endif
354
355static ssize_t sh_sub_read(int fd, void *buf, size_t count)
356{
357  char * mbuf = (char *) buf;
358  ssize_t rcount;
359  int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
360  int tti = 1; 
361
362  do {
363    rcount = read(fd, mbuf, count);
364
365    if (rcount > 0) 
366      {
367        count -= rcount; mbuf += rcount; --ttl;
368      }
369
370    if (count > 0)
371      {
372        if (ttl > 0)
373          {
374            retry_msleep(0, tti);
375            tti *= 9;
376          }
377        else
378          {
379            if (rcount >= 0) 
380              errno = ETIMEDOUT;
381            return -1;
382          }
383      }
384  } while (count > 0 && 
385           (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR));
386
387  if (count > 0)
388    return -1;
389
390  return 0;
391}
392
393#ifdef SH_SUB_DBG
394#include <stdarg.h>
395static void debug_it (const char *fmt, ...)
396{
397  char msg[256];
398  va_list ap;
399
400  int fd = open("debug.it", O_CREAT|O_WRONLY|O_APPEND, 0666);
401
402  va_start(ap, fmt);
403  vsnprintf(msg, sizeof(msg), fmt, ap);  /* flawfinder: ignore */
404  va_end(ap);
405
406  write(fd, msg, strlen(msg));
407  write(fd, "\n", 1);
408  close(fd);
409  return;
410}
411#endif
412
413static int sh_sub_stat_int(const char *path, struct stat *buf, char command)
414{
415  int retval;
416  volatile int sflag = 0;
417  struct sh_sub_in  inbuf;
418  struct sh_sub_out outbuf;
419  struct pollfd     pfds;
420
421  size_t len = strlen(path) + 1;
422
423  if (len > SH_SUB_BUF)
424    {
425      if (command == SH_COM_LSTAT)
426        {
427          do { 
428            retval = lstat(path, buf); 
429          } while (retval < 0 && errno == EAGAIN);
430
431          return retval;
432        }
433      else
434        {
435          do { 
436            retval = stat(path, buf); 
437          } while (retval < 0 && errno == EAGAIN);
438
439          return retval;
440        }
441    }
442
443  sl_strlcpy(inbuf.path, path, SH_SUB_BUF);
444  inbuf.command = command;
445
446 start:
447
448#ifdef SH_SUB_DBG
449  debug_it("%d sh_child_pid %d\n", (int)getpid(), (int) sh_child_pid);
450#endif
451
452  if (sh_child_pid == -1)
453    sh_create_sub();
454
455#ifdef SH_SUB_DBG
456  debug_it("%d stat_sub %s (%d)\n", (int)getpid(), inbuf.path, (int) sh_child_pid);
457#endif
458
459  SH_MUTEX_LOCK(mutex_sub_work);
460
461  retval = sh_sub_write(parent2child[1], &inbuf, sizeof(inbuf));
462  if (retval < 0)
463    {
464      int error = errno;
465      sh_kill_sub();
466      errno = error;
467      sflag = 1;
468      goto end;
469    }
470
471#ifdef SH_SUB_DBG
472  debug_it("%d stat_sub polling..\n", (int)getpid());
473#endif
474
475  pfds.fd     = child2parent[0];
476  pfds.events = POLLIN;
477
478  do {
479    retval = poll(&pfds, 1, 300 * 1000);
480  } while (retval < 0 && errno == EINTR);
481
482  if (retval <= 0)
483    {
484      int error = errno;
485      sh_kill_sub();
486      errno = (retval == 0) ? ETIMEDOUT : error;
487      sflag = -1;
488      goto end;
489    }
490
491#ifdef SH_SUB_DBG
492  debug_it("%d stat_sub reading..\n", (int)getpid());
493#endif
494
495  retval = sh_sub_read (child2parent[0], &outbuf, sizeof(outbuf));
496  if (retval < 0)
497    {
498      int error = errno;
499      sh_kill_sub();
500      errno = error;
501      sflag = 1;
502      goto end;
503    }
504
505 end:
506  ; /* 'label at end of compound statement' */
507  SH_MUTEX_UNLOCK(mutex_sub_work);
508
509  if      (sflag == 0)
510    {
511#ifdef SH_SUB_DBG
512      debug_it("%d stat_sub done..\n", (int)getpid());
513#endif
514      memcpy(buf, &(outbuf.sbuf), sizeof(struct stat));
515      errno = outbuf.errnum;
516      return outbuf.retval;
517    }
518  else if (sflag == 1)
519    {
520#ifdef SH_SUB_DBG
521      debug_it("%d stat_sub error..\n", (int)getpid());
522#endif
523      /* could not read, thus subprocess may have gone */
524      sflag = 0;
525      goto start;
526    }
527
528  return -1;
529}
530
531int sh_sub_stat (const char *path, struct stat *buf)
532{
533  return sh_sub_stat_int(path, buf, SH_COM_STAT);
534}
535
536int sh_sub_lstat(const char *path, struct stat *buf)
537{
538  return sh_sub_stat_int(path, buf, SH_COM_LSTAT);
539}
540
Note: See TracBrowser for help on using the repository browser.