source: trunk/src/sh_processcheck.c@ 390

Last change on this file since 390 was 384, checked in by katerina, 13 years ago

Fix for ticket #282 (compile issues on FreeBSD).

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