source: trunk/src/sh_processcheck.c@ 76

Last change on this file since 76 was 76, checked in by rainer, 18 years ago

Fix for ticket #38 (csv escaping) and #39 (building on cygwin). Also optimize a bit.

File size: 27.4 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2006 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/***************************************************************************
21 *
22 * This file provides a module for samhain to check for hidden/faked/missing
23 * processes on the host.
24 *
25 */
26
27#include "config_xor.h"
28
29#define _XOPEN_SOURCE 500
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <ctype.h>
34#include <string.h>
35#include <sys/types.h>
36#include <dirent.h>
37#include <sys/stat.h>
38#include <signal.h>
39#include <unistd.h>
40
41#ifdef _POSIX_PRIORITY_SCHEDULING
42#include <sched.h>
43#endif
44
45#ifdef HAVE_GETPRIORITY
46#include <errno.h>
47#include <sys/resource.h>
48#endif
49
50#ifdef HAVE_REGEX_H
51#include <regex.h>
52#endif
53
54#include "samhain.h"
55#include "sh_modules.h"
56#include "sh_processcheck.h"
57#include "sh_utils.h"
58#include "sh_error.h"
59#include "sh_extern.h"
60
61#ifdef SH_USE_PROCESSCHECK
62
63#define FIL__ _("sh_processcheck.c")
64
65#ifdef __linux__
66#define HAVE_THREADS
67#endif
68
69/* We won't want to build this into yule
70 */
71#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
72
73/* sh_prochk_maxpid is one more than the largest pid
74 */
75static size_t sh_prochk_minpid = 0x0001;
76static size_t sh_prochk_maxpid = 0x8000;
77static size_t sh_prochk_size = 0;
78
79static int ShProchkActive = S_TRUE;
80static short * sh_prochk_res = NULL;
81
82static char * sh_prochk_pspath = NULL;
83static char * sh_prochk_psarg = NULL;
84
85#define SH_PROCHK_INTERVAL 300
86static time_t sh_prochk_interval = SH_PROCHK_INTERVAL;
87static int sh_prochk_severity = SH_ERR_SEVERE;
88
89
90static int sh_prochk_set_maxpid (const char * str);
91static int sh_prochk_set_minpid (const char * str);
92static int sh_prochk_set_active (const char *str);
93static int sh_prochk_add_process (const char *str);
94static int sh_prochk_set_pspath (const char *str);
95static int sh_prochk_set_psarg (const char *str);
96static int sh_prochk_set_interval(const char *str);
97static int sh_prochk_set_severity(const char *str);
98
99sh_rconf sh_prochk_table[] = {
100 {
101 N_("severityprocesscheck"),
102 sh_prochk_set_severity,
103 },
104 {
105 N_("processcheckexists"),
106 sh_prochk_add_process,
107 },
108 {
109 N_("processcheckactive"),
110 sh_prochk_set_active,
111 },
112 {
113 N_("processcheckminpid"),
114 sh_prochk_set_minpid,
115 },
116 {
117 N_("processcheckmaxpid"),
118 sh_prochk_set_maxpid,
119 },
120 {
121 N_("processcheckpspath"),
122 sh_prochk_set_pspath,
123 },
124 {
125 N_("processcheckpsarg"),
126 sh_prochk_set_psarg,
127 },
128 {
129 N_("processcheckinterval"),
130 sh_prochk_set_interval,
131 },
132 {
133 NULL,
134 NULL
135 }
136};
137
138#define SH_PROC_MISSING 1
139#define SH_PROC_FAKED 2
140#define SH_PROC_HIDDEN 4
141#define SH_PROC_EXISTS 8
142
143#ifndef HAVE_LSTAT
144#define lstat(x,y) stat(x,y)
145#endif /* HAVE_LSTAT */
146
147static const short SH_PR_PS = 0x0001;
148
149static const short SH_PR_GETSID = 0x0002;
150static const short SH_PR_KILL = 0x0004;
151static const short SH_PR_GETPGID = 0x0008;
152
153static const short SH_PR_LSTAT = 0x0010;
154static const short SH_PR_OPENDIR = 0x0020;
155static const short SH_PR_CHDIR = 0x0040;
156static const short SH_PR_SCHED = 0x0080;
157
158static const short SH_PR_PRIORITY = 0x0100;
159
160static const short SH_PR_PS2 = 0x0200;
161static const short SH_PR_PS_ANY = 0x0400;
162static const short SH_PR_ALL = 0x0800;
163static const short SH_PR_ANY = 0x1000;
164
165struct watchlist {
166 char * str;
167 unsigned long pid;
168#ifdef HAVE_REGEX_H
169 regex_t preg;
170#endif
171 int seen;
172
173 struct watchlist *next;
174};
175
176static struct watchlist * process_check = NULL;
177
178static struct watchlist * list_missing = NULL;
179static struct watchlist * list_fake = NULL;
180static struct watchlist * list_hidden = NULL;
181
182/* recursively remove all list entries
183 */
184static void kill_list (struct watchlist * head)
185{
186 if (head->next)
187 kill_list (head->next);
188
189 if (head->str)
190 SH_FREE(head->str);
191 SH_FREE(head);
192
193 return;
194}
195
196
197/* check the list for old entries; clean out old entries; reset others
198 * Return number of non-obsolete entries
199 */
200static size_t clean_list (struct watchlist ** head_ptr)
201{
202 size_t count = 0;
203 struct watchlist * ptr = *head_ptr;
204 struct watchlist * pre = *head_ptr;
205
206 while (ptr)
207 {
208 if (ptr->seen == S_FALSE) /* obsolete entry */
209 {
210 if (ptr == pre) /* at head */
211 {
212 ptr = pre->next;
213 *head_ptr = pre->next;
214 if (pre->str)
215 SH_FREE(pre->str);
216 SH_FREE(pre);
217 pre = ptr;
218 }
219 else
220 {
221 pre->next = ptr->next;
222 if (ptr->str)
223 SH_FREE(ptr->str);
224 SH_FREE(ptr);
225 ptr = pre->next;
226 }
227 }
228 else
229 {
230 ++count;
231 ptr->seen = S_FALSE; /* reset status */
232 pre = ptr;
233 ptr = ptr->next;
234 }
235 }
236 return count;
237}
238
239/* check if process is in list; if not, add it and return false
240 */
241static int is_in_list (struct watchlist ** head_ptr,
242 char * str, unsigned long pid)
243{
244 struct watchlist * ptr = *head_ptr;
245
246 if (str)
247 {
248 while (ptr)
249 {
250 if (ptr->str && (0 == strcmp(str, ptr->str)))
251 {
252 ptr->seen = S_TRUE;
253 return S_TRUE;
254 }
255 ptr = ptr->next;
256 }
257 }
258 else
259 {
260 while (ptr)
261 {
262 if (ptr->pid == pid)
263 {
264 ptr->seen = S_TRUE;
265 return S_TRUE;
266 }
267 ptr = ptr->next;
268 }
269 }
270
271 ptr = SH_ALLOC(sizeof(struct watchlist));
272
273 if (str)
274 {
275 ptr->str = sh_util_strdup(str);
276 }
277 else
278 {
279 ptr->str = NULL;
280 ptr->pid = pid;
281 }
282 ptr->next = *head_ptr;
283 ptr->seen = S_TRUE;
284 *head_ptr = ptr;
285
286 return S_FALSE;
287}
288
289static int is_in_watchlist (const char *str, unsigned long num)
290{
291 struct watchlist * list = process_check;
292
293 while (list)
294 {
295#ifdef HAVE_REGEX_H
296 if (0 == regexec(&(list->preg), str, 0, NULL, 0))
297 {
298 list->seen = S_TRUE;
299 list->pid = num;
300 return S_TRUE;
301 }
302#else
303 if (strstr(str, list->str))
304 {
305 list->seen = S_TRUE;
306 list->pid = num;
307 return S_TRUE;
308 }
309#endif
310 list = list->next;
311 }
312 return S_FALSE;
313}
314
315static void check_watchlist (short * res)
316{
317 struct watchlist * list = process_check;
318 char * tmp;
319 size_t indx;
320
321 while (list)
322 {
323 if (list->seen == S_FALSE)
324 {
325 /* avoid repetition of messages
326 */
327 if (S_FALSE == is_in_list(&list_missing, list->str, 0))
328 {
329 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
330 MSG_PCK_MISS,
331 list->str);
332 }
333 }
334 else
335 {
336 indx = list->pid - sh_prochk_minpid;
337
338 if (list->pid < sh_prochk_maxpid && list->pid >= sh_prochk_minpid &&
339 ((res[indx] & SH_PR_ANY) == 0) && /* not found */
340 ((res[indx] & SH_PR_PS) != 0) && /* seen in first ps */
341 ((res[indx] & SH_PR_PS2) != 0)) /* seen in second ps */
342 {
343 /* fake process, thus considered missing
344 */
345 if (S_FALSE == is_in_list(&list_missing, list->str, 0))
346 {
347 tmp = sh_util_safe_name (list->str);
348 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
349 MSG_PCK_MISS,
350 tmp);
351 SH_FREE(tmp);
352 }
353 }
354 list->seen = S_FALSE;
355 }
356 list = list->next;
357 }
358}
359
360/* Add 'str' to the list of watched processes for which
361 * existence should be checked.
362 */
363int sh_prochk_add_process (const char *str)
364{
365 struct watchlist *new;
366 int status;
367 char errbuf[256];
368
369 SL_ENTER(_("sh_prochk_add_process"));
370
371 if( str == NULL )
372 SL_RETURN(-1, _("sh_prochk_add_process") );
373
374 new = SH_ALLOC(sizeof(struct watchlist));
375 new->next = process_check;
376 new->str = sh_util_strdup(str);
377#ifdef HAVE_REGEX_H
378 status = regcomp(&(new->preg), str, REG_NOSUB|REG_EXTENDED);
379 if (status != 0)
380 {
381 regerror(status, &(new->preg), errbuf, sizeof(errbuf));
382 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
383 errbuf, _("sh_processes_runps"));
384 SH_FREE(new->str);
385 SH_FREE(new);
386 SL_RETURN(-1, _("sh_prochk_add_process") );
387 }
388#endif
389 new->pid = 0;
390 new->seen = S_FALSE;
391
392 process_check = new;
393 SL_RETURN(0, _("sh_prochk_add_process") );
394}
395
396/* severity
397 */
398int sh_prochk_set_severity (const char * c)
399{
400 char tmp[32];
401 tmp[0] = '='; tmp[1] = '\0';
402 sl_strlcat (tmp, c, 32);
403 return sh_error_set_level (tmp, &sh_prochk_severity);
404}
405
406
407
408/* Path to ps
409 */
410int sh_prochk_set_pspath(const char *str)
411{
412 SL_ENTER(_("sh_prochk_set_pspath"));
413
414 if (!str && ('/' != str[0]))
415 SL_RETURN((-1), _("sh_prochk_set_psarg"));
416 if (sh_prochk_pspath)
417 SH_FREE(sh_prochk_pspath);
418 sh_prochk_pspath = sh_util_strdup (str);
419
420 SL_RETURN((0), _("sh_prochk_set_pspath"));
421
422}
423
424/* argument for ps
425 */
426int sh_prochk_set_psarg(const char *str)
427{
428 SL_ENTER(_("sh_prochk_set_psarg"));
429
430 if (sh_prochk_psarg)
431 SH_FREE(sh_prochk_psarg);
432 sh_prochk_psarg = sh_util_strdup (str);
433
434 SL_RETURN((0), _("sh_prochk_set_psarg"));
435
436}
437
438
439/* Decide if we're active.
440 */
441int sh_prochk_set_active(const char *str)
442{
443 int value;
444
445 SL_ENTER(_("sh_prochk_set_active"));
446
447 value = sh_util_flagval(str, &ShProchkActive);
448
449 SL_RETURN((value), _("sh_prochk_set_active"));
450}
451
452/* Minimum PID
453 */
454int sh_prochk_set_minpid(const char * str)
455{
456 size_t value;
457 char * foo;
458 int retval = 0;
459
460 SL_ENTER(_("sh_prochk_set_minpid"));
461
462 value = (size_t) strtoul(str, &foo, 0);
463 if (*foo != '\0')
464 retval = -1;
465 else
466 sh_prochk_minpid = value;
467
468 SL_RETURN((retval), _("sh_prochk_set_minpid"));
469}
470
471/* Maximum PID
472 */
473static int userdef_maxpid = 0;
474
475int sh_prochk_set_maxpid(const char * str)
476{
477 size_t value;
478 char * foo;
479 int retval = 0;
480
481 SL_ENTER(_("sh_prochk_set_maxpid"));
482
483 value = (size_t) strtoul(str, &foo, 0);
484 if (*foo != '\0') {
485 retval = -1;
486 } else {
487 sh_prochk_maxpid = value + 1;
488 userdef_maxpid = 1;
489 }
490
491 SL_RETURN((retval), _("sh_prochk_set_maxpid"));
492}
493
494int sh_prochk_set_interval (const char * c)
495{
496 int retval = 0;
497 long val;
498
499 SL_ENTER(_("sh_prochk_set_interval"));
500 val = strtol (c, (char **)NULL, 10);
501 if (val <= 0)
502 {
503 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
504 _("process check interval"), c);
505 retval = -1;
506 }
507
508 val = (val <= 0 ? 60 : val);
509
510 sh_prochk_interval = (time_t) val;
511 SL_RETURN(0, _("sh_prochk_set_interval"));
512}
513
514
515
516/* Recurse to the end of the list and then free the data as we return
517 * back up towards the start, making sure to free any strdupped strings
518 */
519static void sh_prochk_free_list(struct watchlist *head)
520{
521 if ( head != NULL )
522 {
523 sh_prochk_free_list(head->next);
524 if (head->str)
525 SH_FREE(head->str);
526#ifdef HAVE_REGEX_H
527 regfree(&(head->preg));
528#endif
529 SH_FREE(head);
530 }
531 return;
532}
533
534#if defined(__linux__)
535#define PROC_PID_MAX _("/proc/sys/kernel/pid_max")
536
537static int proc_max_pid (size_t * procpid)
538{
539 unsigned long pid;
540 FILE * fd;
541 char str[128];
542 char * ptr;
543
544 SL_ENTER(_("proc_max_pid"));
545
546 if (userdef_maxpid != 0)
547 SL_RETURN((-1), _("proc_max_pid"));
548
549 if (0 == access(PROC_PID_MAX, R_OK)) /* flawfinder: ignore */
550 {
551 if (NULL != (fd = fopen(PROC_PID_MAX, "r")))
552 {
553 str[0] = '\0';
554 fgets(str, 128, fd);
555 if (*str != '\0')
556 {
557 pid = strtoul(str, &ptr, 0);
558 if (*ptr == '\0' || *ptr == '\n')
559 {
560 fclose(fd);
561 *procpid = (size_t) pid;
562 SL_RETURN(0, _("proc_max_pid"));
563 }
564 }
565 fclose(fd);
566 }
567 }
568 SL_RETURN((-1), _("proc_max_pid"));
569}
570#else
571static int proc_max_pid(size_t * dummy)
572{
573 (void) dummy;
574 return -1;
575}
576#endif
577
578static void sh_processes_tlist (char * list, size_t len, short res)
579{
580 if (res & SH_PR_PS) sl_strlcat(list, _(" ps(initial)"), len);
581 if (res & SH_PR_CHDIR) sl_strlcat(list, _(" chdir"), len);
582 if (res & SH_PR_OPENDIR) sl_strlcat(list, _(" opendir"), len);
583 if (res & SH_PR_LSTAT) sl_strlcat(list, _(" lstat"), len);
584 if (res & SH_PR_PRIORITY) sl_strlcat(list, _(" getpriority"), len);
585 if (res & SH_PR_SCHED) sl_strlcat(list, _(" sched_getparam"), len);
586 if (res & SH_PR_GETSID) sl_strlcat(list, _(" getsid"), len);
587 if (res & SH_PR_GETPGID) sl_strlcat(list, _(" getpgid"), len);
588 if (res & SH_PR_KILL) sl_strlcat(list, _(" kill"), len);
589 if (res & SH_PR_PS2) sl_strlcat(list, _(" ps(final)"), len);
590 return;
591}
592
593/* FIXME: add open, statvfs, sched_getaffinity
594 */
595static short sh_processes_check (pid_t pid, short res)
596{
597 int have_checks = 0;
598 int need_checks = 0;
599#ifdef HAVE_PROCFS
600 char path[128];
601 struct stat buf;
602 DIR * dir;
603#endif
604
605#if !defined(sun) && !defined(__sun) && !defined(__sun__)
606#ifdef _POSIX_PRIORITY_SCHEDULING
607 struct sched_param p;
608#endif
609#endif
610
611 if (0 == kill(pid, 0))
612 {
613 res |= SH_PR_KILL; res |= SH_PR_ANY; ++have_checks;
614 ++need_checks;
615 }
616 else if (errno != EPERM)
617 {
618 ++need_checks;
619 }
620
621#ifdef HAVE_GETPGID
622 if ((pid_t)-1 != getpgid(pid))
623 {
624 res |= SH_PR_GETPGID; res |= SH_PR_ANY; ++have_checks;
625 }
626 ++need_checks;
627#endif
628
629#ifdef HAVE_GETSID
630 if ((pid_t)-1 != getsid(pid))
631 {
632 res |= SH_PR_GETSID; res |= SH_PR_ANY; ++have_checks;
633 }
634 ++need_checks;
635#endif
636
637 /* sched_getparam() is broken on solaris 10, may segfault in librt
638 */
639#if !defined(sun) && !defined(__sun) && !defined(__sun__)
640#ifdef _POSIX_PRIORITY_SCHEDULING
641 if (0 == sched_getparam (pid, &p))
642 {
643 res |= SH_PR_SCHED; res |= SH_PR_ANY; ++have_checks;
644 }
645 ++need_checks;
646#endif
647#endif
648
649#ifdef HAVE_GETPRIORITY
650 errno = 0;
651 if (((-1) == getpriority (PRIO_PROCESS, (int) pid)) && (errno == ESRCH));
652 else
653 {
654 res |= SH_PR_PRIORITY; res |= SH_PR_ANY; ++have_checks;
655 }
656 ++need_checks;
657#endif
658
659#ifdef HAVE_PROCFS
660 sl_snprintf (path, sizeof(path), "/proc/%ld", (unsigned long) pid);
661
662 if (0 == lstat (path, &buf))
663 {
664 res |= SH_PR_LSTAT; res |= SH_PR_ANY; ++have_checks;
665 }
666 ++need_checks;
667
668 if (NULL != (dir = opendir(path)))
669 {
670 res |= SH_PR_OPENDIR; res |= SH_PR_ANY; ++have_checks;
671 closedir(dir);
672 }
673 ++need_checks;
674
675#if !defined(SH_PROFILE)
676 if (0 == chdir(path))
677 {
678 res |= SH_PR_CHDIR; res |= SH_PR_ANY; ++have_checks;
679 retry_aud_chdir(FIL__, __LINE__, "/");
680 }
681 ++need_checks;
682#endif
683#endif
684
685 if (have_checks == need_checks)
686 {
687 res |= SH_PR_ALL;
688 }
689 return res;
690}
691
692static int sh_processes_readps (FILE * in, short * res,
693 char * str, size_t len,
694 short flag, pid_t pid)
695{
696 int cc;
697 unsigned int lnum = 0;
698 unsigned long num = 0;
699 char c;
700 unsigned int pos = 0;
701 char tstr[256];
702 enum { SKIP_WS, SKIP_WS2, GET_NUM, SKIP_END, GET_NUM2 } line;
703
704 SL_ENTER(_("sh_processes_readps"));
705
706 if (!in) {
707 SL_RETURN((-1), _("sh_processes_readps"));
708 }
709
710 tstr[(sizeof(tstr)-1)] = '\0';
711 tstr[0] = '\0';
712 line = SKIP_END; /* Skip 1st line */
713
714 do
715 {
716 cc = fgetc(in);
717
718 if (EOF == cc)
719 {
720 if (feof(in))
721 {
722 break;
723 }
724 else if (errno == EAGAIN)
725 {
726 continue;
727 }
728 else
729 {
730 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
731 sh_error_message(errno),
732 _("sh_processes_readps"));
733 break;
734 }
735 }
736
737 c = (char) cc;
738
739 if (pos < (sizeof(tstr)-1))
740 {
741 tstr[pos] = c; ++pos;
742 }
743
744 switch(line)
745 {
746 case SKIP_END:
747 if (c == '\n')
748 {
749 tstr[pos-1] = '\0';
750 /* fprintf(stderr, "<%ld> %s\n", num, tstr); */
751 line = SKIP_WS; pos = 0;
752 if (str != NULL && num == (unsigned long) pid)
753 sl_strlcpy(str, tstr, len);
754 if (lnum != 0)
755 is_in_watchlist (tstr, num);
756 ++lnum;
757 }
758 break;
759 case SKIP_WS:
760 if (isspace(cc))
761 break;
762 num = 0;
763 line = GET_NUM;
764 /* fallthrough */
765 case GET_NUM:
766 if (isdigit(cc))
767 {
768 num = num * 10 + (c - '0');
769 break;
770 }
771#ifdef HAVE_THREADS
772 num = 0;
773 line = SKIP_WS2;
774#else
775 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
776 {
777 res[num - sh_prochk_minpid] |= flag;
778 }
779 line = SKIP_END;
780#endif
781 break;
782 case SKIP_WS2:
783 if (isspace(cc))
784 break;
785 num = 0;
786 line = GET_NUM2;
787 /* fallthrough */
788 case GET_NUM2:
789 if (isdigit(cc))
790 {
791 num = num * 10 + (c - '0');
792 break;
793 }
794 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
795 {
796 res[num - sh_prochk_minpid] |= flag;
797 }
798 line = SKIP_END;
799 break;
800 default:
801 SL_RETURN ((-1), _("sh_processes_readps"));
802 }
803 } while (1);
804
805 if (ferror(in))
806 {
807 SL_RETURN ((-1), _("sh_processes_readps"));
808 }
809
810 SL_RETURN ((0), _("sh_processes_readps"));
811}
812
813static int sh_processes_runps (short * res, char * str, size_t len,
814 short flag, pid_t pid)
815{
816 sh_tas_t task;
817
818 int status = 0;
819 char * p;
820 struct sigaction new_act;
821 struct sigaction old_act;
822 int retval = 0;
823
824 SL_ENTER(_("sh_processes_runps"));
825
826 sh_ext_tas_init(&task);
827 p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid);
828 if (p)
829 {
830 (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
831 }
832 (void) sh_ext_tas_add_envv (&task, _("SHELL"),
833 _("/bin/sh"));
834 (void) sh_ext_tas_add_envv (&task, _("PATH"),
835 _("/sbin:/usr/sbin:/bin:/usr/bin"));
836 if (sh.timezone != NULL)
837 {
838 (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
839 }
840
841 if (!sh_prochk_pspath)
842 sh_ext_tas_command(&task, PSPATH);
843 else
844 sh_ext_tas_command(&task, sh_prochk_pspath);
845
846 (void) sh_ext_tas_add_argv(&task, _("ps"));
847
848 if (!sh_prochk_psarg)
849 {
850#ifdef HAVE_THREADS
851 (void) sh_ext_tas_add_argv(&task, _("-eT"));
852#else
853 (void) sh_ext_tas_add_argv(&task, PSARG);
854#endif
855 }
856 else
857 {
858 (void) sh_ext_tas_add_argv(&task, sh_prochk_psarg);
859 }
860
861 task.rw = 'r';
862 task.fork_twice = S_FALSE;
863
864 status = sh_ext_popen(&task);
865 if (status != 0)
866 {
867 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
868 _("Could not open pipe"), _("sh_processes_runps"));
869 SL_RETURN ((-1), _("sh_processes_runps"));
870 }
871
872 /* ignore SIGPIPE (instead get EPIPE if connection is closed)
873 */
874 new_act.sa_handler = SIG_IGN;
875 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
876
877 /* read from the open pipe
878 */
879 if (task.pipe != NULL)
880 {
881 retval = sh_processes_readps (task.pipe, res, str, len, flag, pid);
882 }
883
884 /* restore old signal handler
885 */
886 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
887
888 /* close pipe and return exit status
889 */
890 (void) sh_ext_pclose(&task);
891 SL_RETURN ((retval), _("sh_processes_runps"));
892}
893
894static int sh_process_check_int (short * res)
895{
896 size_t i, j;
897 char tests[512];
898
899 pid_t this_pid;
900
901 SL_ENTER(_("sh_process_check_int"));
902
903 this_pid = getpid();
904
905 if (!res)
906 {
907 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
908 _("Internal error: NULL argument"),
909 _("sh_process_check_int"));
910 SL_RETURN ((-1), _("sh_process_check_int"));
911 }
912
913 sh_processes_runps (res, NULL, 0, SH_PR_PS, 0);
914 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
915 {
916 j = i - sh_prochk_minpid;
917 res[j] = sh_processes_check ((pid_t) i, res[j]);
918 }
919 sh_processes_runps (res, NULL, 0, SH_PR_PS2, 0);
920
921 /* Evaluate results
922 */
923 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
924 {
925 /* don't check the current process
926 */
927 if (i == (size_t) this_pid)
928 continue;
929
930 j = i - sh_prochk_minpid;
931
932 if (((res[j] & SH_PR_PS) != 0) || ((res[j] & SH_PR_PS2) != 0))
933 {
934 res[j] |= SH_PR_PS_ANY;
935 }
936 else
937 {
938 res[j] &= ~SH_PR_PS_ANY;
939 }
940
941 tests[0] = '\0';
942
943 if ((res[j] & SH_PR_ANY) || (res[j] & SH_PR_PS_ANY))
944 {
945 sh_processes_tlist (tests, sizeof(tests), res[j]);
946 /*
947 * case 1: in ps and found
948 */
949 if ((res[j] & SH_PR_PS_ANY) && (res[j] & SH_PR_ANY))
950 {
951 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_OK,
952 (unsigned long) i, tests);
953 }
954
955 /*
956 * case 2: not in ps and found
957 */
958 else if ((res[j] & SH_PR_PS_ANY) == 0)
959 {
960 res[j] = sh_processes_check ((pid_t) i, 0);
961 /*
962 * if still there, it is real and hidden
963 */
964 if (res[j] & SH_PR_ANY)
965 {
966 if (S_FALSE == is_in_list(&list_hidden, NULL, i))
967 {
968 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
969 MSG_PCK_HIDDEN,
970 (unsigned long) i, tests);
971 }
972 }
973 }
974
975 /*
976 * case 3: in ps, but not found
977 */
978 else
979 {
980 if (((res[j] & SH_PR_PS) != 0) && ((res[j] & SH_PR_PS2) != 0))
981 {
982 if (S_FALSE == is_in_list(&list_fake, NULL, i))
983 {
984 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
985 MSG_PCK_FAKE,
986 (unsigned long) i, tests);
987 }
988 }
989 }
990 }
991 } /* loop end */
992
993 check_watchlist (res);
994
995 SL_RETURN (0, _("sh_process_check_int"));
996}
997
998/* Initialise.
999 */
1000int sh_prochk_init(void)
1001{
1002 SL_ENTER(_("sh_prochk_init"));
1003
1004 (void) proc_max_pid (&sh_prochk_maxpid);
1005
1006 if (sh_prochk_minpid > sh_prochk_maxpid)
1007 ShProchkActive = S_FALSE;
1008
1009 /* We need to free anything allocated by the configuration functions if
1010 * we find that the module is to be left inactive - otherwise _reconf()
1011 * won't quite work.
1012 */
1013 if( ShProchkActive == S_FALSE )
1014 {
1015 sh_prochk_free_list(process_check);
1016 process_check = NULL;
1017 SL_RETURN(-1, _("sh_prochk_init"));
1018 }
1019
1020 sh_prochk_size = sh_prochk_maxpid - sh_prochk_minpid;
1021
1022 sh_prochk_res = SH_ALLOC(sizeof(short) * sh_prochk_size);
1023 memset (sh_prochk_res, 0, sizeof(short) * sh_prochk_size);
1024
1025 SL_RETURN(0, _("sh_prochk_init"));
1026}
1027
1028
1029int sh_prochk_timer(time_t tcurrent)
1030{
1031 static time_t lastcheck = 0;
1032
1033 SL_ENTER(_("sh_prochk_timer"));
1034 if ((time_t) (tcurrent - lastcheck) >= sh_prochk_interval)
1035 {
1036 lastcheck = tcurrent;
1037 SL_RETURN((-1), _("sh_prochk_timer"));
1038 }
1039 SL_RETURN(0, _("sh_prochk_timer"));
1040}
1041
1042int sh_prochk_check(void)
1043{
1044 int status = 0;
1045
1046 SL_ENTER(_("sh_prochk_check"));
1047
1048 if( ShProchkActive != S_FALSE )
1049 {
1050 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_CHECK,
1051 (unsigned long) sh_prochk_minpid,
1052 (unsigned long) (sh_prochk_maxpid-1));
1053 status = sh_process_check_int(sh_prochk_res);
1054 if (status != 0)
1055 ShProchkActive = S_FALSE;
1056
1057 /* clean out old entries which are not marked
1058 * as missing/hidden/fake anymore
1059 */
1060 clean_list (&list_missing);
1061 clean_list (&list_hidden);
1062 clean_list (&list_fake);
1063 }
1064
1065 SL_RETURN(status, _("sh_prochk_check"));
1066}
1067
1068/* Free our lists and the associated memory
1069 */
1070int sh_prochk_cleanup(void)
1071{
1072 SL_ENTER(_("sh_prochk_cleanup"));
1073
1074 sh_prochk_reconf();
1075
1076 if (list_missing) {
1077 kill_list(list_missing);
1078 list_missing = NULL;
1079 }
1080 if (list_hidden) {
1081 kill_list(list_hidden);
1082 list_hidden = NULL;
1083 }
1084 if (list_fake) {
1085 kill_list(list_fake);
1086 list_fake = NULL;
1087 }
1088
1089 SL_RETURN(0, _("sh_prochk_cleanup"));
1090}
1091
1092/* Free our lists and the associated memory
1093 */
1094int sh_prochk_reconf(void)
1095{
1096 SL_ENTER(_("sh_prochk_reconf"));
1097
1098 userdef_maxpid = 0;
1099 sh_prochk_maxpid = 0x8000;
1100 sh_prochk_minpid = 0x0000;
1101 sh_prochk_interval = SH_PROCHK_INTERVAL;
1102
1103 sh_prochk_free_list(process_check);
1104 process_check = NULL;
1105 if (sh_prochk_res != NULL)
1106 SH_FREE(sh_prochk_res);
1107 sh_prochk_res = NULL;
1108
1109 if (sh_prochk_psarg)
1110 SH_FREE(sh_prochk_psarg);
1111 sh_prochk_psarg = NULL;
1112 if (sh_prochk_pspath)
1113 SH_FREE(sh_prochk_pspath);
1114 sh_prochk_pspath = NULL;
1115
1116 SL_RETURN(0, _("sh_prochk_reconf"));
1117}
1118
1119/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
1120#endif
1121
1122/* #ifdef SH_USE_PROCESSCHECK */
1123#endif
1124
1125
1126#ifdef SH_CUTEST
1127#include "CuTest.h"
1128
1129void Test_processcheck_watchlist_ok (CuTest *tc) {
1130#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1131 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1132 CuAssertTrue(tc,
1133 S_TRUE == is_in_watchlist(" 1 ? 00:00:00 init", 0));
1134 CuAssertTrue(tc,
1135 S_FALSE == is_in_watchlist(" 1 ? 00:00:00 flix", 0));
1136 CuAssertTrue(tc,
1137 S_TRUE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/init -k start -DSSL", 0));
1138 CuAssertTrue(tc,
1139 S_FALSE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/apache2 -k start -DSSL", 0));
1140
1141
1142 sh_prochk_free_list(process_check);
1143 process_check = NULL;
1144 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1145
1146 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1147 CuAssertTrue(tc, 0 == sh_prochk_add_process("ssh"));
1148 CuAssertTrue(tc, 0 == sh_prochk_add_process("syslog"));
1149 CuAssertTrue(tc, S_TRUE == is_in_watchlist("init", 0));
1150 CuAssertTrue(tc, S_TRUE == is_in_watchlist("ssh", 0));
1151 CuAssertTrue(tc, S_TRUE == is_in_watchlist("syslog", 0));
1152
1153 sh_prochk_free_list(process_check);
1154 process_check = NULL;
1155 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1156 CuAssertTrue(tc, S_FALSE == is_in_watchlist("ssh", 0));
1157 CuAssertTrue(tc, S_FALSE == is_in_watchlist("syslog", 0));
1158#else
1159 (void) tc; /* fix compiler warning */
1160#endif
1161 return;
1162}
1163
1164void Test_processcheck_listhandle_ok (CuTest *tc) {
1165#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1166 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1167 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1168 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1169 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1170
1171 if (list_missing)
1172 kill_list(list_missing);
1173 list_missing = NULL;
1174
1175 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1176 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1177 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1178 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1179
1180 if (list_missing)
1181 kill_list(list_missing);
1182 list_missing = NULL;
1183
1184 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1185 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1186 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1187 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1188
1189 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1190 CuAssertPtrNotNull(tc, list_missing);
1191
1192 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1193 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1194
1195 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1196 CuAssertPtrNotNull(tc, list_missing);
1197
1198 CuAssertTrue(tc, 0 == clean_list(&list_missing));
1199 CuAssertTrue(tc, NULL == list_missing);
1200#else
1201 (void) tc; /* fix compiler warning */
1202#endif
1203 return;
1204}
1205
1206
1207/* #ifdef SH_CUTEST */
1208#endif
1209
Note: See TracBrowser for help on using the repository browser.