source: trunk/src/sh_schedule.c@ 532

Last change on this file since 532 was 481, checked in by katerina, 9 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.