source: trunk/src/sh_processcheck.c@ 550

Last change on this file since 550 was 539, checked in by katerina, 6 years ago

Fixes for tickets #431 (OpenBSD compatibility) and #432 (compiler warnings).

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