source: trunk/src/sh_sub.c@ 479

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

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

File size: 11.0 KB
RevLine 
[316]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
[321]22/* 0->1 for debug */
23#if 0
24#define SH_SUB_DBG 1
25#endif
26
[316]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
[321]69void sh_kill_sub()
[316]70{
71 SH_MUTEX_LOCK(mutex_sub);
[321]72
[316]73 if (sh_child_pid != -1)
74 {
75 int status;
[321]76#ifdef WCONTINUED
77 int wflags = WNOHANG|WUNTRACED|WCONTINUED;
78#else
79 int wflags = WNOHANG|WUNTRACED;
80#endif
[316]81
82 close (parent2child[1]);
83 close (child2parent[0]);
84
[321]85 /* fprintf(stderr, "FIXME kill_sub %d\n", (int) sh_child_pid); */
[316]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)
[321]93 sh_wait_ret = waitpid( -1, &status, wflags);
[316]94 else
[321]95 sh_wait_ret = waitpid(sh_child_pid, &status, wflags);
[316]96
97 sh_child_pid = -1;
98 }
[321]99
[316]100 SH_MUTEX_UNLOCK(mutex_sub);
101 return;
102}
103
104static int sh_create_sub()
105{
106 pid_t res;
[321]107 volatile int retval = 0;
[316]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
[321]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
[316]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:
[323]232 ; /* 'label at end of compound statement' */
[316]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{
[429]254 char * mbuf = (char *) buf;
[316]255 ssize_t rcount;
256 int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
257 int tti = 1;
258
259 do {
260
[429]261 rcount = write(fd, mbuf, count);
[316]262 if (rcount > 0)
263 {
[429]264 count -= rcount; mbuf += rcount; --ttl;
[316]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
[321]298 /* fprintf(stderr, "FIXME wait_com polling..\n"); */
[316]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
[321]330 /* fprintf(stderr, "FIXME wait_com writing..\n"); */
[316]331
332 ret = sh_sub_write(child2parent[1], &outbuf, sizeof(outbuf));
333 if (ret < 0)
334 {
[321]335 /* fprintf(stderr, "FIXME wait_com return 1\n"); */
[316]336 return;
337 }
338 }
339 else /* sh_sub_read() < 0 */
340 {
[321]341 /* fprintf(stderr, "FIXME wait_com return 2\n"); */
[316]342 return;
343 }
344 }
345
[321]346 /* fprintf(stderr, "FIXME wait_com next..\n"); */
[316]347
348 } while (1 == 1);
349}
350
[325]351#ifndef ETIMEDOUT
352#define ETIMEDOUT EIO
353#endif
354
[316]355static ssize_t sh_sub_read(int fd, void *buf, size_t count)
356{
[429]357 char * mbuf = (char *) buf;
[316]358 ssize_t rcount;
359 int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
360 int tti = 1;
361
362 do {
[429]363 rcount = read(fd, mbuf, count);
[316]364
365 if (rcount > 0)
366 {
[429]367 count -= rcount; mbuf += rcount; --ttl;
[316]368 }
369
370 if (count > 0)
371 {
372 if (ttl > 0)
373 {
374 retry_msleep(0, tti);
375 tti *= 9;
376 }
377 else
378 {
[325]379 if (rcount >= 0)
380 errno = ETIMEDOUT;
[316]381 return -1;
382 }
383 }
[325]384 } while (count > 0 &&
385 (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR));
[316]386
387 if (count > 0)
388 return -1;
389
390 return 0;
391}
392
[321]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
[316]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
[321]448#ifdef SH_SUB_DBG
449 debug_it("%d sh_child_pid %d\n", (int)getpid(), (int) sh_child_pid);
450#endif
451
[316]452 if (sh_child_pid == -1)
453 sh_create_sub();
454
[321]455#ifdef SH_SUB_DBG
456 debug_it("%d stat_sub %s (%d)\n", (int)getpid(), inbuf.path, (int) sh_child_pid);
457#endif
[316]458
459 SH_MUTEX_LOCK(mutex_sub_work);
460
461 retval = sh_sub_write(parent2child[1], &inbuf, sizeof(inbuf));
462 if (retval < 0)
463 {
[324]464 int error = errno;
[316]465 sh_kill_sub();
[324]466 errno = error;
[316]467 sflag = 1;
468 goto end;
469 }
470
[321]471#ifdef SH_SUB_DBG
472 debug_it("%d stat_sub polling..\n", (int)getpid());
473#endif
[316]474
475 pfds.fd = child2parent[0];
476 pfds.events = POLLIN;
477
478 do {
[324]479 retval = poll(&pfds, 1, 300 * 1000);
[316]480 } while (retval < 0 && errno == EINTR);
481
482 if (retval <= 0)
483 {
[324]484 int error = errno;
[316]485 sh_kill_sub();
[324]486 errno = (retval == 0) ? ETIMEDOUT : error;
[316]487 sflag = -1;
488 goto end;
489 }
490
[321]491#ifdef SH_SUB_DBG
492 debug_it("%d stat_sub reading..\n", (int)getpid());
493#endif
[316]494
495 retval = sh_sub_read (child2parent[0], &outbuf, sizeof(outbuf));
496 if (retval < 0)
497 {
[324]498 int error = errno;
[316]499 sh_kill_sub();
[324]500 errno = error;
[316]501 sflag = 1;
502 goto end;
503 }
504
505 end:
[323]506 ; /* 'label at end of compound statement' */
[316]507 SH_MUTEX_UNLOCK(mutex_sub_work);
508
509 if (sflag == 0)
510 {
[321]511#ifdef SH_SUB_DBG
512 debug_it("%d stat_sub done..\n", (int)getpid());
513#endif
[316]514 memcpy(buf, &(outbuf.sbuf), sizeof(struct stat));
515 errno = outbuf.errnum;
516 return outbuf.retval;
517 }
518 else if (sflag == 1)
519 {
[321]520#ifdef SH_SUB_DBG
521 debug_it("%d stat_sub error..\n", (int)getpid());
522#endif
[316]523 /* could not read, thus subprocess may have gone */
[321]524 sflag = 0;
[316]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.