source: trunk/src/sh_processcheck.c@ 102

Last change on this file since 102 was 102, checked in by rainer, 17 years ago

Flush before fork (fix for ticket #60), and fix for kcheck on 2.6.21 (ticket #63).

File size: 30.0 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_WS, 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_WS:
864 if (isspace(cc))
865 break;
866 num = 0;
867 line = GET_NUM;
868 /* fallthrough */
869 case GET_NUM:
870 if (isdigit(cc))
871 {
872 num = num * 10 + (c - '0');
873 break;
874 }
875#ifdef HAVE_THREADS
876 num = 0;
877 line = SKIP_WS2;
878#else
879 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
880 {
881 res[num - sh_prochk_minpid] |= flag;
882 }
883 line = SKIP_END;
884#endif
885 break;
886 case SKIP_WS2:
887 if (isspace(cc))
888 break;
889 num = 0;
890 line = GET_NUM2;
891 /* fallthrough */
892 case GET_NUM2:
893 if (isdigit(cc))
894 {
895 num = num * 10 + (c - '0');
896 break;
897 }
898 if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
899 {
900 res[num - sh_prochk_minpid] |= flag;
901 }
902 line = SKIP_END;
903 break;
904 default:
905 SL_RETURN ((-1), _("sh_processes_readps"));
906 }
907 } while (1);
908
909 if (ferror(in))
910 {
911 SL_RETURN ((-1), _("sh_processes_readps"));
912 }
913
914 SL_RETURN ((0), _("sh_processes_readps"));
915}
916
917static int sh_processes_runps (short * res, char * str, size_t len,
918 short flag, pid_t pid)
919{
920 sh_tas_t task;
921
922 int status = 0;
923 char * p;
924 struct sigaction new_act;
925 struct sigaction old_act;
926 int retval = 0;
927
928 SL_ENTER(_("sh_processes_runps"));
929
930 sh_ext_tas_init(&task);
931 p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid);
932 if (p)
933 {
934 (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
935 }
936 (void) sh_ext_tas_add_envv (&task, _("SHELL"),
937 _("/bin/sh"));
938 (void) sh_ext_tas_add_envv (&task, _("PATH"),
939 _("/sbin:/usr/sbin:/bin:/usr/bin"));
940 if (sh.timezone != NULL)
941 {
942 (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
943 }
944
945 if (!sh_prochk_pspath)
946 sh_ext_tas_command(&task, PSPATH);
947 else
948 sh_ext_tas_command(&task, sh_prochk_pspath);
949
950 (void) sh_ext_tas_add_argv(&task, _("ps"));
951
952 if (!sh_prochk_psarg)
953 {
954#ifdef HAVE_THREADS
955 (void) sh_ext_tas_add_argv(&task, _("-eT"));
956#else
957 (void) sh_ext_tas_add_argv(&task, PSARG);
958#endif
959 }
960 else
961 {
962 (void) sh_ext_tas_add_argv(&task, sh_prochk_psarg);
963 }
964
965 task.rw = 'r';
966 task.fork_twice = S_FALSE;
967
968 status = sh_ext_popen(&task);
969 if (status != 0)
970 {
971 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
972 _("Could not open pipe"), _("sh_processes_runps"));
973 SL_RETURN ((-1), _("sh_processes_runps"));
974 }
975
976 /* ignore SIGPIPE (instead get EPIPE if connection is closed)
977 */
978 new_act.sa_handler = SIG_IGN;
979 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
980
981 /* read from the open pipe
982 */
983 if (task.pipe != NULL)
984 {
985 retval = sh_processes_readps (task.pipe, res, str, len, flag, pid);
986 }
987
988 /* restore old signal handler
989 */
990 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
991
992 /* close pipe and return exit status
993 */
994 (void) sh_ext_pclose(&task);
995 SL_RETURN ((retval), _("sh_processes_runps"));
996}
997
998static int sh_process_check_int (short * res)
999{
1000 size_t i, j;
1001 char tests[512];
1002
1003 pid_t this_pid;
1004
1005 SL_ENTER(_("sh_process_check_int"));
1006
1007 this_pid = getpid();
1008
1009 if (!res)
1010 {
1011 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1012 _("Internal error: NULL argument"),
1013 _("sh_process_check_int"));
1014 SL_RETURN ((-1), _("sh_process_check_int"));
1015 }
1016
1017 sh_processes_runps (res, NULL, 0, SH_PR_PS, 0);
1018 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
1019 {
1020 j = i - sh_prochk_minpid;
1021 res[j] = sh_processes_check ((pid_t) i, res[j]);
1022 }
1023 sh_processes_runps (res, NULL, 0, SH_PR_PS2, 0);
1024
1025 /* Evaluate results
1026 */
1027 for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
1028 {
1029 /* don't check the current process
1030 */
1031 if (i == (size_t) this_pid)
1032 continue;
1033
1034 j = i - sh_prochk_minpid;
1035
1036 if (((res[j] & SH_PR_PS) != 0) || ((res[j] & SH_PR_PS2) != 0))
1037 {
1038 res[j] |= SH_PR_PS_ANY;
1039 }
1040 else
1041 {
1042 res[j] &= ~SH_PR_PS_ANY;
1043 }
1044
1045 tests[0] = '\0';
1046
1047 if ((res[j] & SH_PR_ANY) || (res[j] & SH_PR_PS_ANY))
1048 {
1049 /* list all tests where the pid was found
1050 */
1051 sh_processes_tlist (tests, sizeof(tests), res[j]);
1052
1053 /*
1054 * case 1: in ps and found
1055 */
1056 if ((res[j] & SH_PR_PS_ANY) && (res[j] & SH_PR_ANY))
1057 {
1058 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_OK,
1059 (unsigned long) i, tests);
1060 }
1061
1062 /*
1063 * case 2: not in ps and found
1064 */
1065 else if ((res[j] & SH_PR_PS_ANY) == 0)
1066 {
1067 res[j] = sh_processes_check ((pid_t) i, 0);
1068 /*
1069 * if still there, it is real and hidden
1070 */
1071 if (res[j] & SH_PR_ANY)
1072 {
1073 if (S_FALSE == is_in_list(&list_hidden, NULL, i))
1074 {
1075 char user[16];
1076 char * aout;
1077 char * safe;
1078
1079 aout = get_user_and_path ((pid_t) i, user, sizeof(user));
1080
1081 if (aout)
1082 {
1083 safe = sh_util_safe_name (aout);
1084 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
1085 MSG_PCK_P_HIDDEN,
1086 (unsigned long) i, tests, safe, user);
1087 SH_FREE(safe);
1088 SH_FREE(aout);
1089 }
1090 else
1091 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
1092 MSG_PCK_HIDDEN,
1093 (unsigned long) i, tests);
1094
1095 }
1096 }
1097 }
1098
1099 /*
1100 * case 3: in ps, but not found
1101 */
1102 else
1103 {
1104 if (((res[j] & SH_PR_PS) != 0) && ((res[j] & SH_PR_PS2) != 0))
1105 {
1106 if (S_FALSE == is_in_list(&list_fake, NULL, i))
1107 {
1108 sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
1109 MSG_PCK_FAKE,
1110 (unsigned long) i, tests);
1111 }
1112 }
1113 }
1114 }
1115 } /* loop end */
1116
1117 check_watchlist (res);
1118
1119 SL_RETURN (0, _("sh_process_check_int"));
1120}
1121
1122/* Initialise.
1123 */
1124int sh_prochk_init(void)
1125{
1126 SL_ENTER(_("sh_prochk_init"));
1127
1128 (void) proc_max_pid (&sh_prochk_maxpid);
1129
1130 if (sh_prochk_minpid > sh_prochk_maxpid)
1131 ShProchkActive = S_FALSE;
1132
1133 /* We need to free anything allocated by the configuration functions if
1134 * we find that the module is to be left inactive - otherwise _reconf()
1135 * won't quite work.
1136 */
1137 if( ShProchkActive == S_FALSE )
1138 {
1139 sh_prochk_free_list(process_check);
1140 process_check = NULL;
1141 SL_RETURN(-1, _("sh_prochk_init"));
1142 }
1143
1144 sh_prochk_size = sh_prochk_maxpid - sh_prochk_minpid;
1145
1146 sh_prochk_res = SH_ALLOC(sizeof(short) * sh_prochk_size);
1147 memset (sh_prochk_res, 0, sizeof(short) * sh_prochk_size);
1148
1149 SL_RETURN(0, _("sh_prochk_init"));
1150}
1151
1152
1153int sh_prochk_timer(time_t tcurrent)
1154{
1155 static time_t lastcheck = 0;
1156
1157 SL_ENTER(_("sh_prochk_timer"));
1158 if ((time_t) (tcurrent - lastcheck) >= sh_prochk_interval)
1159 {
1160 lastcheck = tcurrent;
1161 SL_RETURN((-1), _("sh_prochk_timer"));
1162 }
1163 SL_RETURN(0, _("sh_prochk_timer"));
1164}
1165
1166int sh_prochk_check(void)
1167{
1168 int status = 0;
1169
1170 SL_ENTER(_("sh_prochk_check"));
1171
1172 if( ShProchkActive != S_FALSE )
1173 {
1174 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_CHECK,
1175 (unsigned long) sh_prochk_minpid,
1176 (unsigned long) (sh_prochk_maxpid-1));
1177 status = sh_process_check_int(sh_prochk_res);
1178 if (status != 0)
1179 ShProchkActive = S_FALSE;
1180
1181 /* clean out old entries which are not marked
1182 * as missing/hidden/fake anymore
1183 */
1184 clean_list (&list_missing);
1185 clean_list (&list_hidden);
1186 clean_list (&list_fake);
1187 }
1188
1189 SL_RETURN(status, _("sh_prochk_check"));
1190}
1191
1192/* Free our lists and the associated memory
1193 */
1194int sh_prochk_cleanup(void)
1195{
1196 SL_ENTER(_("sh_prochk_cleanup"));
1197
1198 sh_prochk_reconf();
1199
1200 if (list_missing) {
1201 kill_list(list_missing);
1202 list_missing = NULL;
1203 }
1204 if (list_hidden) {
1205 kill_list(list_hidden);
1206 list_hidden = NULL;
1207 }
1208 if (list_fake) {
1209 kill_list(list_fake);
1210 list_fake = NULL;
1211 }
1212
1213 SL_RETURN(0, _("sh_prochk_cleanup"));
1214}
1215
1216/* Free our lists and the associated memory
1217 */
1218int sh_prochk_reconf(void)
1219{
1220 SL_ENTER(_("sh_prochk_reconf"));
1221
1222 userdef_maxpid = 0;
1223 sh_prochk_maxpid = 0x8000;
1224 sh_prochk_minpid = 0x0000;
1225 sh_prochk_interval = SH_PROCHK_INTERVAL;
1226
1227 sh_prochk_free_list(process_check);
1228 process_check = NULL;
1229 if (sh_prochk_res != NULL)
1230 SH_FREE(sh_prochk_res);
1231 sh_prochk_res = NULL;
1232
1233 if (sh_prochk_psarg)
1234 SH_FREE(sh_prochk_psarg);
1235 sh_prochk_psarg = NULL;
1236 if (sh_prochk_pspath)
1237 SH_FREE(sh_prochk_pspath);
1238 sh_prochk_pspath = NULL;
1239
1240 SL_RETURN(0, _("sh_prochk_reconf"));
1241}
1242
1243/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
1244#endif
1245
1246/* #ifdef SH_USE_PROCESSCHECK */
1247#endif
1248
1249
1250#ifdef SH_CUTEST
1251#include "CuTest.h"
1252
1253void Test_processcheck_watchlist_ok (CuTest *tc) {
1254#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1255 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1256 CuAssertTrue(tc,
1257 S_TRUE == is_in_watchlist(" 1 ? 00:00:00 init", 0));
1258 CuAssertTrue(tc,
1259 S_FALSE == is_in_watchlist(" 1 ? 00:00:00 flix", 0));
1260 CuAssertTrue(tc,
1261 S_TRUE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/init -k start -DSSL", 0));
1262 CuAssertTrue(tc,
1263 S_FALSE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/apache2 -k start -DSSL", 0));
1264
1265
1266 sh_prochk_free_list(process_check);
1267 process_check = NULL;
1268 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1269
1270 CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
1271 CuAssertTrue(tc, 0 == sh_prochk_add_process("ssh"));
1272 CuAssertTrue(tc, 0 == sh_prochk_add_process("syslog"));
1273 CuAssertTrue(tc, S_TRUE == is_in_watchlist("init", 0));
1274 CuAssertTrue(tc, S_TRUE == is_in_watchlist("ssh", 0));
1275 CuAssertTrue(tc, S_TRUE == is_in_watchlist("syslog", 0));
1276
1277 sh_prochk_free_list(process_check);
1278 process_check = NULL;
1279 CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
1280 CuAssertTrue(tc, S_FALSE == is_in_watchlist("ssh", 0));
1281 CuAssertTrue(tc, S_FALSE == is_in_watchlist("syslog", 0));
1282#else
1283 (void) tc; /* fix compiler warning */
1284#endif
1285 return;
1286}
1287
1288void Test_processcheck_listhandle_ok (CuTest *tc) {
1289#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
1290 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1291 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1292 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1293 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1294
1295 if (list_missing)
1296 kill_list(list_missing);
1297 list_missing = NULL;
1298
1299 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1300 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1301 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1302 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1303
1304 if (list_missing)
1305 kill_list(list_missing);
1306 list_missing = NULL;
1307
1308 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
1309 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1310 CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
1311 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1312
1313 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1314 CuAssertPtrNotNull(tc, list_missing);
1315
1316 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
1317 CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
1318
1319 CuAssertTrue(tc, 2 == clean_list(&list_missing));
1320 CuAssertPtrNotNull(tc, list_missing);
1321
1322 CuAssertTrue(tc, 0 == clean_list(&list_missing));
1323 CuAssertTrue(tc, NULL == list_missing);
1324#else
1325 (void) tc; /* fix compiler warning */
1326#endif
1327 return;
1328}
1329
1330
1331/* #ifdef SH_CUTEST */
1332#endif
1333
Note: See TracBrowser for help on using the repository browser.