source: trunk/src/sh_processcheck.c@ 67

Last change on this file since 67 was 67, checked in by katerina, 18 years ago

Add/delete files for samhain 2.3

File size: 27.3 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))
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
593static short sh_processes_check (pid_t pid, short res)
594{
595 int have_checks = 0;
596 int need_checks = 0;
597#ifdef HAVE_PROCFS
598 char path[128];
599 struct stat buf;
600 DIR * dir;
601#endif
602
603#if !defined(sun) && !defined(__sun) && !defined(__sun__)
604#ifdef _POSIX_PRIORITY_SCHEDULING
605 struct sched_param p;
606#endif
607#endif
608
609 if (0 == kill(pid, 0))
610 {
611 res |= SH_PR_KILL; res |= SH_PR_ANY; ++have_checks;
612 ++need_checks;
613 }
614 else if (errno != EPERM)
615 {
616 ++need_checks;
617 }
618
619#ifdef HAVE_GETPGID
620 if ((pid_t)-1 != getpgid(pid))
621 {
622 res |= SH_PR_GETPGID; res |= SH_PR_ANY; ++have_checks;
623 }
624 ++need_checks;
625#endif
626
627#ifdef HAVE_GETSID
628 if ((pid_t)-1 != getsid(pid))
629 {
630 res |= SH_PR_GETSID; res |= SH_PR_ANY; ++have_checks;
631 }
632 ++need_checks;
633#endif
634
635 /* sched_getparam() is broken on solaris 10, may segfault in librt
636 */
637#if !defined(sun) && !defined(__sun) && !defined(__sun__)
638#ifdef _POSIX_PRIORITY_SCHEDULING
639 if (0 == sched_getparam (pid, &p))
640 {
641 res |= SH_PR_SCHED; res |= SH_PR_ANY; ++have_checks;
642 }
643 ++need_checks;
644#endif
645#endif
646
647#ifdef HAVE_GETPRIORITY
648 errno = 0;
649 if (((-1) == getpriority (PRIO_PROCESS, (int) pid)) && (errno == ESRCH));
650 else
651 {
652 res |= SH_PR_PRIORITY; res |= SH_PR_ANY; ++have_checks;
653 }
654 ++need_checks;
655#endif
656
657#ifdef HAVE_PROCFS
658 sl_snprintf (path, sizeof(path), "/proc/%ld", (unsigned long) pid);
659
660 if (0 == lstat (path, &buf))
661 {
662 res |= SH_PR_LSTAT; res |= SH_PR_ANY; ++have_checks;
663 }
664 ++need_checks;
665
666 if (NULL != (dir = opendir(path)))
667 {
668 res |= SH_PR_OPENDIR; res |= SH_PR_ANY; ++have_checks;
669 closedir(dir);
670 }
671 ++need_checks;
672
673#if !defined(SH_PROFILE)
674 if (0 == chdir(path))
675 {
676 res |= SH_PR_CHDIR; res |= SH_PR_ANY; ++have_checks;
677 retry_aud_chdir(FIL__, __LINE__, "/");
678 }
679 ++need_checks;
680#endif
681#endif
682
683 if (have_checks == need_checks)
684 {
685 res |= SH_PR_ALL;
686 }
687 return res;
688}
689
690static int sh_processes_readps (FILE * in, short * res,
691 char * str, size_t len,
692 short flag, pid_t pid)
693{
694 int cc;
695 unsigned int lnum = 0;
696 unsigned long num = 0;
697 char c;
698 unsigned int pos = 0;
699 char tstr[256];
700 enum { SKIP_WS, SKIP_WS2, GET_NUM, SKIP_END, GET_NUM2 } line;
701
702 SL_ENTER(_("sh_processes_readps"));
703
704 if (!in) {
705 SL_RETURN((-1), _("sh_processes_readps"));
706 }
707
708 tstr[(sizeof(tstr)-1)] = '\0';
709 tstr[0] = '\0';
710 line = SKIP_END; /* Skip 1st line */
711
712 do
713 {
714 cc = fgetc(in);
715
716 if (EOF == cc)
717 {
718 if (feof(in))
719 {
720 break;
721 }
722 else if (errno == EAGAIN)
723 {
724 continue;
725 }
726 else
727 {
728 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
729 sh_error_message(errno),
730 _("sh_processes_readps"));
731 break;
732 }
733 }
734
735 c = (char) cc;
736
737 if (pos < (sizeof(tstr)-1))
738 {
739 tstr[pos] = c; ++pos;
740 }
741
742 switch(line)
743 {
744 case SKIP_END:
745 if (c == '\n')
746 {
747 tstr[pos-1] = '\0';
748 /* fprintf(stderr, "<%ld> %s\n", num, tstr); */
749 line = SKIP_WS; pos = 0;
750 if (str != NULL && num == (unsigned long) pid)
751 sl_strlcpy(str, tstr, len);
752 if (lnum != 0)
753 is_in_watchlist (tstr, num);
754 ++lnum;
755 }
756 break;
757 case SKIP_WS:
758 if (isspace(cc))
759 break;
760 num = 0;
761 line = GET_NUM;
762 /* fallthrough */
763 case GET_NUM:
764 if (isdigit(cc))
765 {
766 num = num * 10 + (c - '0');
767 break;
768 }
769#ifdef HAVE_THREADS
770 num = 0;
771 line = SKIP_WS2;
772#else
773 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
774 {
775 res[num - sh_prochk_minpid] |= flag;
776 }
777 line = SKIP_END;
778#endif
779 break;
780 case SKIP_WS2:
781 if (isspace(cc))
782 break;
783 num = 0;
784 line = GET_NUM2;
785 /* fallthrough */
786 case GET_NUM2:
787 if (isdigit(cc))
788 {
789 num = num * 10 + (c - '0');
790 break;
791 }
792 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
793 {
794 res[num - sh_prochk_minpid] |= flag;
795 }
796 line = SKIP_END;
797 break;
798 default:
799 SL_RETURN ((-1), _("sh_processes_readps"));
800 }
801 } while (1);
802
803 if (ferror(in))
804 {
805 SL_RETURN ((-1), _("sh_processes_readps"));
806 }
807
808 SL_RETURN ((0), _("sh_processes_readps"));
809}
810
811static int sh_processes_runps (short * res, char * str, size_t len,
812 short flag, pid_t pid)
813{
814 sh_tas_t task;
815
816 int status = 0;
817 char * p;
818 struct sigaction new_act;
819 struct sigaction old_act;
820 int retval = 0;
821
822 SL_ENTER(_("sh_processes_runps"));
823
824 sh_ext_tas_init(&task);
825 p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid);
826 if (p)
827 {
828 (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
829 }
830 (void) sh_ext_tas_add_envv (&task, _("SHELL"),
831 _("/bin/sh"));
832 (void) sh_ext_tas_add_envv (&task, _("PATH"),
833 _("/sbin:/usr/sbin:/bin:/usr/bin"));
834 if (sh.timezone != NULL)
835 {
836 (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
837 }
838
839 if (!sh_prochk_pspath)
840 sh_ext_tas_command(&task, PSPATH);
841 else
842 sh_ext_tas_command(&task, sh_prochk_pspath);
843
844 (void) sh_ext_tas_add_argv(&task, _("ps"));
845
846 if (!sh_prochk_psarg)
847 {
848#ifdef HAVE_THREADS
849 (void) sh_ext_tas_add_argv(&task, _("-eT"));
850#else
851 (void) sh_ext_tas_add_argv(&task, PSARG);
852#endif
853 }
854 else
855 {
856 (void) sh_ext_tas_add_argv(&task, sh_prochk_psarg);
857 }
858
859 task.rw = 'r';
860 task.fork_twice = S_FALSE;
861
862 status = sh_ext_popen(&task);
863 if (status != 0)
864 {
865 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
866 _("Could not open pipe"), _("sh_processes_runps"));
867 SL_RETURN ((-1), _("sh_processes_runps"));
868 }
869
870 /* ignore SIGPIPE (instead get EPIPE if connection is closed)
871 */
872 new_act.sa_handler = SIG_IGN;
873 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
874
875 /* read from the open pipe
876 */
877 if (task.pipe != NULL)
878 {
879 retval = sh_processes_readps (task.pipe, res, str, len, flag, pid);
880 }
881
882 /* restore old signal handler
883 */
884 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
885
886 /* close pipe and return exit status
887 */
888 (void) sh_ext_pclose(&task);
889 SL_RETURN ((retval), _("sh_processes_runps"));
890}
891
892static int sh_process_check_int (short * res)
893{
894 size_t i, j;
895 char tests[512];
896
897 pid_t this_pid;
898
899 SL_ENTER(_("sh_process_check_int"));
900
901 this_pid = getpid();
902
903 if (!res)
904 {
905 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
906 _("Internal error: NULL argument"),
907 _("sh_process_check_int"));
908 SL_RETURN ((-1), _("sh_process_check_int"));
909 }
910
911 sh_processes_runps (res, NULL, 0, SH_PR_PS, 0);
912 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
913 {
914 j = i - sh_prochk_minpid;
915 res[j] = sh_processes_check ((pid_t) i, res[j]);
916 }
917 sh_processes_runps (res, NULL, 0, SH_PR_PS2, 0);
918
919 /* Evaluate results
920 */
921 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
922 {
923 /* don't check the current process
924 */
925 if (i == (size_t) this_pid)
926 continue;
927
928 j = i - sh_prochk_minpid;
929
930 if (((res[j] & SH_PR_PS) != 0) || ((res[j] & SH_PR_PS2) != 0))
931 {
932 res[j] |= SH_PR_PS_ANY;
933 }
934 else
935 {
936 res[j] &= ~SH_PR_PS_ANY;
937 }
938
939 tests[0] = '\0';
940
941 if ((res[j] & SH_PR_ANY) || (res[j] & SH_PR_PS_ANY))
942 {
943 sh_processes_tlist (tests, sizeof(tests), res[j]);
944 /*
945 * case 1: in ps and found
946 */
947 if ((res[j] & SH_PR_PS_ANY) && (res[j] & SH_PR_ANY))
948 {
949 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_OK,
950 (unsigned long) i, tests);
951 }
952
953 /*
954 * case 2: not in ps and found
955 */
956 else if ((res[j] & SH_PR_PS_ANY) == 0)
957 {
958 res[j] = sh_processes_check ((pid_t) i, 0);
959 /*
960 * if still there, it is real and hidden
961 */
962 if (res[j] & SH_PR_ANY)
963 {
964 if (S_FALSE == is_in_list(&list_hidden, NULL, i))
965 {
966 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
967 MSG_PCK_HIDDEN,
968 (unsigned long) i, tests);
969 }
970 }
971 }
972
973 /*
974 * case 3: in ps, but not found
975 */
976 else
977 {
978 if (((res[j] & SH_PR_PS) != 0) && ((res[j] & SH_PR_PS2) != 0))
979 {
980 if (S_FALSE == is_in_list(&list_fake, NULL, i))
981 {
982 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
983 MSG_PCK_FAKE,
984 (unsigned long) i, tests);
985 }
986 }
987 }
988 }
989 } /* loop end */
990
991 check_watchlist (res);
992
993 SL_RETURN (0, _("sh_process_check_int"));
994}
995
996/* Initialise.
997 */
998int sh_prochk_init(void)
999{
1000 SL_ENTER(_("sh_prochk_init"));
1001
1002 (void) proc_max_pid (&sh_prochk_maxpid);
1003
1004 if (sh_prochk_minpid > sh_prochk_maxpid)
1005 ShProchkActive = S_FALSE;
1006
1007 /* We need to free anything allocated by the configuration functions if
1008 * we find that the module is to be left inactive - otherwise _reconf()
1009 * won't quite work.
1010 */
1011 if( ShProchkActive == S_FALSE )
1012 {
1013 sh_prochk_free_list(process_check);
1014 process_check = NULL;
1015 SL_RETURN(-1, _("sh_prochk_init"));
1016 }
1017
1018 sh_prochk_size = sh_prochk_maxpid - sh_prochk_minpid;
1019
1020 sh_prochk_res = SH_ALLOC(sizeof(short) * sh_prochk_size);
1021 memset (sh_prochk_res, 0, sizeof(short) * sh_prochk_size);
1022
1023 SL_RETURN(0, _("sh_prochk_init"));
1024}
1025
1026
1027int sh_prochk_timer(time_t tcurrent)
1028{
1029 static time_t lastcheck = 0;
1030
1031 SL_ENTER(_("sh_prochk_timer"));
1032 if ((time_t) (tcurrent - lastcheck) >= sh_prochk_interval)
1033 {
1034 lastcheck = tcurrent;
1035 SL_RETURN((-1), _("sh_prochk_timer"));
1036 }
1037 SL_RETURN(0, _("sh_prochk_timer"));
1038}
1039
1040int sh_prochk_check(void)
1041{
1042 int status = 0;
1043
1044 SL_ENTER(_("sh_prochk_check"));
1045
1046 if( ShProchkActive != S_FALSE )
1047 {
1048 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_CHECK,
1049 (unsigned long) sh_prochk_minpid,
1050 (unsigned long) (sh_prochk_maxpid-1));
1051 status = sh_process_check_int(sh_prochk_res);
1052 if (status != 0)
1053 ShProchkActive = S_FALSE;
1054
1055 /* clean out old entries which are not marked
1056 * as missing/hidden/fake anymore
1057 */
1058 clean_list (&list_missing);
1059 clean_list (&list_hidden);
1060 clean_list (&list_fake);
1061 }
1062
1063 SL_RETURN(status, _("sh_prochk_check"));
1064}
1065
1066/* Free our lists and the associated memory
1067 */
1068int sh_prochk_cleanup(void)
1069{
1070 SL_ENTER(_("sh_prochk_cleanup"));
1071
1072 sh_prochk_reconf();
1073
1074 if (list_missing) {
1075 kill_list(list_missing);
1076 list_missing = NULL;
1077 }
1078 if (list_hidden) {
1079 kill_list(list_hidden);
1080 list_hidden = NULL;
1081 }
1082 if (list_fake) {
1083 kill_list(list_fake);
1084 list_fake = NULL;
1085 }
1086
1087 SL_RETURN(0, _("sh_prochk_cleanup"));
1088}
1089
1090/* Free our lists and the associated memory
1091 */
1092int sh_prochk_reconf(void)
1093{
1094 SL_ENTER(_("sh_prochk_reconf"));
1095
1096 userdef_maxpid = 0;
1097 sh_prochk_maxpid = 0x8000;
1098 sh_prochk_minpid = 0x0000;
1099 sh_prochk_interval = SH_PROCHK_INTERVAL;
1100
1101 sh_prochk_free_list(process_check);
1102 process_check = NULL;
1103 if (sh_prochk_res != NULL)
1104 SH_FREE(sh_prochk_res);
1105 sh_prochk_res = NULL;
1106
1107 if (sh_prochk_psarg)
1108 SH_FREE(sh_prochk_psarg);
1109 sh_prochk_psarg = NULL;
1110 if (sh_prochk_pspath)
1111 SH_FREE(sh_prochk_pspath);
1112 sh_prochk_pspath = NULL;
1113
1114 SL_RETURN(0, _("sh_prochk_reconf"));
1115}
1116
1117/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
1118#endif
1119
1120/* #ifdef SH_USE_PROCESSCHECK */
1121#endif
1122
1123
1124#ifdef SH_CUTEST
1125#include "CuTest.h"
1126
1127void Test_processcheck_watchlist_ok (CuTest *tc) {
1128#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1129 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1130 CuAssertTrue(tc,
1131 S_TRUE == is_in_watchlist(" 1 ? 00:00:00 init", 0));
1132 CuAssertTrue(tc,
1133 S_FALSE == is_in_watchlist(" 1 ? 00:00:00 flix", 0));
1134 CuAssertTrue(tc,
1135 S_TRUE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/init -k start -DSSL", 0));
1136 CuAssertTrue(tc,
1137 S_FALSE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/apache2 -k start -DSSL", 0));
1138
1139
1140 sh_prochk_free_list(process_check);
1141 process_check = NULL;
1142 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1143
1144 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1145 CuAssertTrue(tc, 0 == sh_prochk_add_process("ssh"));
1146 CuAssertTrue(tc, 0 == sh_prochk_add_process("syslog"));
1147 CuAssertTrue(tc, S_TRUE == is_in_watchlist("init", 0));
1148 CuAssertTrue(tc, S_TRUE == is_in_watchlist("ssh", 0));
1149 CuAssertTrue(tc, S_TRUE == is_in_watchlist("syslog", 0));
1150
1151 sh_prochk_free_list(process_check);
1152 process_check = NULL;
1153 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1154 CuAssertTrue(tc, S_FALSE == is_in_watchlist("ssh", 0));
1155 CuAssertTrue(tc, S_FALSE == is_in_watchlist("syslog", 0));
1156#else
1157 (void) tc; /* fix compiler warning */
1158#endif
1159 return;
1160}
1161
1162void Test_processcheck_listhandle_ok (CuTest *tc) {
1163#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1164 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1165 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1166 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1167 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1168
1169 if (list_missing)
1170 kill_list(list_missing);
1171 list_missing = NULL;
1172
1173 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1174 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1175 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1176 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1177
1178 if (list_missing)
1179 kill_list(list_missing);
1180 list_missing = NULL;
1181
1182 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1183 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1184 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1185 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1186
1187 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1188 CuAssertPtrNotNull(tc, list_missing);
1189
1190 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1191 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1192
1193 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1194 CuAssertPtrNotNull(tc, list_missing);
1195
1196 CuAssertTrue(tc, 0 == clean_list(&list_missing));
1197 CuAssertTrue(tc, NULL == list_missing);
1198#else
1199 (void) tc; /* fix compiler warning */
1200#endif
1201 return;
1202}
1203
1204
1205/* #ifdef SH_CUTEST */
1206#endif
1207
Note: See TracBrowser for help on using the repository browser.