source: trunk/src/sh_processcheck.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 27 hours ago

Fixes for compiler warnings.

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