source: trunk/src/sh_processcheck.c@ 101

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

Fix for compile failure on FreeBSD 6.1

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