source: trunk/src/sh_processcheck.c@ 376

Last change on this file since 376 was 374, checked in by katerina, 13 years ago

Patch for ticket #255 (intruder on server). Also disable setting prelink/ps path with --disable-shellexpand.

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