source: trunk/src/sh_sub.c@ 318

Last change on this file since 318 was 316, checked in by katerina, 14 years ago

Missing files for ticket #236

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