source: trunk/src/sh_processcheck.c@ 169

Last change on this file since 169 was 169, checked in by katerina, 16 years ago

Fixes for tickes #93 to #104 (yes, big commit, bad, bad,...).

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