source: trunk/src/sh_schedule.c @ 481

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

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 9.8 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2002 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#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26
27#include <errno.h>
28#include <sys/types.h>
29#include <unistd.h>
30
31/*
32   gcc -Wall -O2 -o mysched sh_schedule.c -DTESTONLY
33 */
34#ifndef TESTONLY
35
36
37#undef  FIL__
38#define FIL__  _("sh_schedule.c")
39
40#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
41#define SCHEDULER_YES
42#endif
43
44#if TIME_WITH_SYS_TIME
45#include <sys/time.h>
46#include <time.h>
47#else
48#if HAVE_SYS_TIME_H
49#include <sys/time.h>
50#else
51#include <time.h>
52#endif
53#endif
54
[22]55#include "samhain.h"
[1]56#include "sh_mem.h"
[481]57#include "sh_error_min.h"
[1]58
59/* TESTONLY */
60#else
61
62#define SCHEDULER_YES
63#include <time.h>
64
65#endif
66
67#include "sh_schedule.h"
68
69
70
71#ifdef SCHEDULER_YES
72
73/************************************************
74 *
75 * Scheduler class - private area
76 *
77 ************************************************/
78
79
80static const int  sh_schedule_max[5] = { 59, 23, 31, 12, 7 };
81static const int  sh_schedule_min[5] = {  0,  0,  0,  0, 0 };
82
83static
84int test_val (int i, int min, int max, int min_step, 
85              time_t * last, time_t now, int nval, int first_flag)
86{
87  /* don't miss a minute's task
88   * IDEA:  set last = now after first check (? seems to work)
89   */
90  if (i == 0 && max == min && nval > max
91      /* && ( ((now - *last) > min_step) || (*last == (time_t)-1) ) */ )
92    {
93      if (*last == (time_t)-1)
94        {
95          /* fake execution at nval-max
96           */
97          *last = now - 60 * (nval-max);
98          return 0;
99        }
100      if ((int)(now - *last) > min_step)
101        return 1;
102    }
103
104  /* out of range
105   */
106  if (nval > max || nval < min) 
107    return 0;
108
109  /* first call - invalid last_exec
110
111  if (*last == (time_t)-1)
112    return 1;
113  */
114
115  if (first_flag == 0)
116    return 1;
117
118
119  /* before min_step - too early (e.g. same minute)
120   */
121  if ((int)(now - *last) <= min_step)
122    return 0;
123
124  return 1;
125}
126
127static
128int test_sched_int (sh_schedule_t * isched)
129{
130  time_t now;
131  struct tm * tval;
132  int count, i, nval;
[131]133#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
134  struct tm     time_tm;
135#endif
[1]136
137  if (!isched)
138    return 0;
139
140  now  = time(NULL);
[131]141#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
142  tval = localtime_r(&now, &time_tm);
143#else
[1]144  tval = localtime(&now);
[131]145#endif
[481]146
147  if (!tval)
148    {
149      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
150                       _("localime() failed"), _("test_sched_int") );
151      return 0;
152    }
153
[1]154  count = 0;
155  for (i = 0; i < 5; ++i)
156    {
157      if      (i == 0) nval = tval->tm_min;
158      else if (i == 1) nval = tval->tm_hour;
159      else if (i == 2) nval = tval->tm_mday;
160      else if (i == 3) nval = tval->tm_mon;
161      else             nval = tval->tm_wday;
162      count += test_val (i, isched->min[i], isched->max[i], 
163                         isched->min_step, &(isched->last_exec), 
164                         now, nval, isched->first);
165    }
166
167  if (count == 5)
168    {
169      isched->first = 1;
170      isched->last_exec = now;
171      return 1;
172    }
173
174  return 0;
175}
176
177/* test a linked list of schedules
178 */
179int test_sched (sh_schedule_t * isched)
180{
181  sh_schedule_t * intern = isched;
182  int             retval = 0;
183
184  while (intern != NULL)
185    {
186      if (test_sched_int(intern) == 1)
187        retval = 1;
188      intern = intern->next;
189    }
190  return retval;
191}
192
193static 
194char DayNames[7][4] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
195static
196char MonNames[12][4] = { "jan", "feb", "mar", "apr", "may", "jun", 
197                       "jul", "aug", "sep", "oct", "nov", "dec" };
198
199static
200int parse_func (int i, char * p)
201{
202  int j, k, l;
203  char *tail;
204
205  errno = 0;
206  j = (int) strtol(p, &tail, 10);
207
208  if (errno != 0)     /* overflow          */
209    return -1;
210  if (j < 0)
211    return -1;
212  if (tail != p)      /* numeric           */
213    return j;
214  if (i < 3)          /* names not allowed */
215    return -1;
216
217  if (i == 3)
218    {
219      for (j = 0; j < 12; ++j) {
220        l = 0;
221        /*@+charint@*//* Incompatible types for == (char, char): ??? */
222        for (k = 0; k < 3; ++k)
[290]223          if (p[k] != '\0' && tolower((int) p[k]) == MonNames[j][k]) ++l;
[1]224        /*@-charint@*/
225        if (l == 3)
226          return j;
227      }
228    }
229  if (i == 4)
230    {
231      for (j = 0; j < 7; ++j) {
232        l = 0;
233        /*@+charint@*//* Incompatible types for == (char, char): ??? */
234        for (k = 0; k < 3; ++k)
[290]235          if (p[k] != '\0' && tolower((int) p[k]) == DayNames[j][k]) ++l;
[1]236        /*@-charint@*/
237        if (l == 3)
238          return j;
239      }
240    }
241
242  return -1;
243} 
244
245static
246int parse_token(int i, sh_schedule_t * isched, char * p)
247{
248  char * q;
249
250  if ( NULL != (q = strchr(p, ',')))
251    return -1;
252
253  if (*p == '*')
254    {
255      isched->min[i] = sh_schedule_min[i];
256      isched->max[i] = sh_schedule_max[i];
257    }
258  else 
259    {
260      isched->min[i] = parse_func(i, p);
261      if (i == 4 && isched->min[i] == 7)
262        isched->min[i] = 0;
263      if (isched->min[i] < sh_schedule_min[i] || 
264          isched->min[i] > sh_schedule_max[i])
265        {
266          return -1;
267        }
268      if ( NULL != (q = strchr(p, '-')))
269        {
270          ++q;
271          isched->max[i] = parse_func(i, q);
272          if (i == 4 && isched->max[i] == 7)
273            isched->max[i] = 0;
274          if (isched->max[i] < sh_schedule_min[i] || 
275              isched->max[i] > sh_schedule_max[i] ||
276              isched->max[i] < isched->min[i])
277            {
278              return -1;
279            }
280        }
281      else
282        isched->max[i] = isched->min[i];
283    }
284
285  if ( NULL != (q = strchr(p, '/')))
286    {
287      ++q;
288      isched->step[i] = atoi(q);
289      if (isched->step[i] < 1 || isched->step[i] > sh_schedule_max[i])
290        {
291          return -1;
292        }
293      if (i == 4 && isched->step[i] == 7)
294        isched->step[i] = 6;
295    }
296  else
297    {
298      isched->step[i] = 1;
299    }
300
301  switch (i) 
302    {
303    case 0:
304      if (isched->max[i] == isched->min[i])
305        isched->min_step = 3599;
306      else
307        isched->min_step = (isched->step[i] * 60) - 1;
308      break;
309    case 1:
310      if (isched->max[i] == isched->min[i])
311        {
312          /* fix for daylight saving time: subtract 3600 sec
313           */
314          if (isched->min_step == 3599)
315            isched->min_step = 86399 - 3600;
316        }
317      else
318        {
319          if (isched->min_step == 3599)
320            isched->min_step = (isched->step[i] * 3600) - 1;
321        }
322      break;
323    default:
324      break;
325    }
326     
327  return 0;
328}
329
330static
331int parse_sched (const char * ssched, sh_schedule_t * isched)
332{
333  char * p;
334  char * copy;
335  int    i = 0;
[22]336  size_t len;
[131]337#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
338  char * saveptr;
339#endif
[1]340
341  if (!ssched || !isched)
342    return -1;
343
[22]344  len = strlen(ssched)+1;
[1]345#ifdef TESTONLY
[454]346  copy = calloc(1,len);                 /* testonly code */
[1]347#else
[22]348  copy = SH_ALLOC(len);
[1]349#endif
[22]350  sl_strlcpy(copy, ssched, len);
[1]351
[131]352#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
353  p = strtok_r(copy, " \t", &saveptr); /* parse crontab-style schedule */
354#else
[1]355  p = strtok(copy, " \t"); /* parse crontab-style schedule */
[131]356#endif
357
[1]358  if (!p)
359    goto err; 
360  if (parse_token(i, isched, p) == -1)
361    goto err;
362
363  for (i = 1; i < 5; ++i)
364    {
[131]365#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
366      p = strtok_r(NULL, " \t", &saveptr); /* parse crontab-style schedule */
367#else
[1]368      p = strtok(NULL, " \t"); /* parse crontab-style schedule */
[131]369#endif
[1]370      if (!p)
371        goto err; 
372      if (parse_token(i, isched, p) == -1)
373        goto err;
374    }
375
376  isched->last_exec = (time_t)-1;
377  isched->first     = 0;
378  isched->next      = NULL;
379
380#ifdef TESTONLY
381  free(copy);
382#else
383  SH_FREE(copy);
384#endif
385  return 0;
386
387 err:
388#ifdef TESTONLY
389  free(copy);
390#else
391  SH_FREE(copy);
392#endif
393  return -1;
394}
395
396int create_sched (const char * ssched, sh_schedule_t * isched)
397{
398  int j;
399
400  if (!isched || !ssched)
401    return -1;
402
403  j = parse_sched(ssched, isched);
404
405#ifdef TESTONLY
406  if (j == 0)
407    {
408      int i;
409      for (i = 0; i < 5; ++i)
410        printf("%2d MIN  %3d  MAX  %3d  STEP  %3d\n", 
411               i, isched->max[i], isched->min[i], isched->step[i]);
412      printf("MINSTEP   %7d\n", isched->min_step);
413      printf("LASTEXEC  %7ld\n", (long) isched->last_exec);
414    }
415#endif
416
417  return j;
418}
419
420/* #ifdef SCHEDULER_YES */
421#endif
422
423/**************************************************
424 *
425 * Schedule class - Test driver
426 *
427 **************************************************/
428#ifdef TESTONLY
429
430int main(int argc, char * argv[])
431{
432  sh_schedule_t isched;
433
434  if (argc < 2)
435    {
436      fprintf(stderr, "Usage: %s 'schedule'\n", argv[0]);
437      exit (1);
438    }
439
440  if (create_sched(argv[1], &isched) < 0)
441    {
442      fprintf(stderr, "Bad schedule <%s>\n", argv[1]);
443      exit (1);
444    }
445
446  while (1 == 1)
447    {
448      if (test_sched(&isched))
[131]449        printf("EXECUTE  at: %s", ctime(&(isched.last_exec))); /* TESTONLY */
[1]450      sleep (1); /* TESTONLY */
451    }
452  return 0;
453}
454#endif
Note: See TracBrowser for help on using the repository browser.