source: trunk/src/sh_processcheck.c@ 127

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

Fix for ticket #59 (process check malfunction).

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