OpenVAS Libraries  9.0.3
nasl_isotime.c
Go to the documentation of this file.
1 /* openvas-libraries/nasl
2  * $Id$
3  * Description: Implementation of an API for ISOTIME values.
4  *
5  * Authors:
6  * Werner Koch <wk@gnupg.org>
7  *
8  * Copyright:
9  * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
10  * Copyright (C) 2012 Greenbone Networks GmbH
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 /* This code is based on code from GnuPG 2.x, file common/gettime.c,
27  commit id 76055d4. The copyright was LGPLv3+ or GPLv2+; we chose
28  GPLv2+. The only author of that code is Werner Koch; who assigned
29  the copyright to the FSF. */
30 
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #include <time.h>
59 #include <glib.h>
60 #include <glib/gstdio.h>
61 
62 #include "nasl_tree.h"
63 #include "nasl_global_ctxt.h"
64 #include "nasl_var.h"
65 #include "nasl_lex_ctxt.h"
66 #include "nasl_debug.h"
67 
68 #include "nasl_isotime.h"
69 
70 
71 #ifndef DIM
72 # define DIM(v) (sizeof(v)/sizeof((v)[0]))
73 # define DIMof(type,member) DIM(((type *)0)->member)
74 #endif
75 
76 /* The type used to represent the time here is a string with a fixed
77  length. */
78 #define ISOTIME_SIZE 16
79 typedef char my_isotime_t[ISOTIME_SIZE];
80 
81 /* Correction used to map to real Julian days. */
82 #define JD_DIFF 1721060L
83 
84 /* Useful helper macros to avoid problems with locales. */
85 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
86 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
87 
88 /* The atoi macros assume that the buffer has only valid digits. */
89 #define atoi_1(p) (*(p) - '0' )
90 #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
91 #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
92 
93 
94 /* Convert an Epoch time to an ISO timestamp. */
95 static void
96 epoch2isotime (my_isotime_t timebuf, time_t atime)
97 {
98  if (atime == (time_t)(-1))
99  *timebuf = 0;
100  else
101  {
102  struct tm *tp;
103 
104  tp = gmtime (&atime);
105  if (snprintf (timebuf, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d",
106  1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
107  tp->tm_hour, tp->tm_min, tp->tm_sec) < 0)
108  {
109  *timebuf = '\0';
110  return;
111  }
112  }
113 }
114 
115 /* Return the current time in ISO format. */
116 static void
117 get_current_isotime (my_isotime_t timebuf)
118 {
119  epoch2isotime (timebuf, time (NULL));
120 }
121 
122 
123 /* Check that the 15 bytes in ATIME represent a valid ISO timestamp.
124  Returns 0 if ATIME has a valid format. Note that this function
125  does not expect a string but a check just the plain 15 bytes of the
126  the buffer without looking at the string terminator. */
127 static int
128 check_isotime (const my_isotime_t atime)
129 {
130  int i;
131  const char *s;
132 
133  if (!*atime)
134  return 1;
135 
136  for (s=atime, i=0; i < 8; i++, s++)
137  if (!digitp (s))
138  return 1;
139  if (*s != 'T')
140  return 1;
141  for (s++, i=9; i < 15; i++, s++)
142  if (!digitp (s))
143  return 1;
144  return 0;
145 }
146 
147 
148 /* Return true if STRING holds an isotime string. The expected format is
149  yyyymmddThhmmss
150  optionally terminated by white space, comma, or a colon.
151  */
152 static int
153 isotime_p (const char *string)
154 {
155  const char *s;
156  int i;
157 
158  if (!*string)
159  return 0;
160  for (s=string, i=0; i < 8; i++, s++)
161  if (!digitp (s))
162  return 0;
163  if (*s != 'T')
164  return 0;
165  for (s++, i=9; i < 15; i++, s++)
166  if (!digitp (s))
167  return 0;
168  if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
169  return 0; /* Wrong delimiter. */
170 
171  return 1;
172 }
173 
174 
175 /* Scan a string and return true if the string represents the human
176  readable format of an ISO time. This format is:
177  yyyy-mm-dd[ hh[:mm[:ss]]]
178  Scanning stops at the second space or at a comma. */
179 static int
180 isotime_human_p (const char *string)
181 {
182  const char *s;
183  int i;
184 
185  if (!*string)
186  return 0;
187  for (s=string, i=0; i < 4; i++, s++)
188  if (!digitp (s))
189  return 0;
190  if (*s != '-')
191  return 0;
192  s++;
193  if (!digitp (s) || !digitp (s+1) || s[2] != '-')
194  return 0;
195  i = atoi_2 (s);
196  if (i < 1 || i > 12)
197  return 0;
198  s += 3;
199  if (!digitp (s) || !digitp (s+1))
200  return 0;
201  i = atoi_2 (s);
202  if (i < 1 || i > 31)
203  return 0;
204  s += 2;
205  if (!*s || *s == ',')
206  return 1; /* Okay; only date given. */
207  if (!spacep (s))
208  return 0;
209  s++;
210  if (spacep (s))
211  return 1; /* Okay, second space stops scanning. */
212  if (!digitp (s) || !digitp (s+1))
213  return 0;
214  i = atoi_2 (s);
215  if (i < 0 || i > 23)
216  return 0;
217  s += 2;
218  if (!*s || *s == ',')
219  return 1; /* Okay; only date and hour given. */
220  if (*s != ':')
221  return 0;
222  s++;
223  if (!digitp (s) || !digitp (s+1))
224  return 0;
225  i = atoi_2 (s);
226  if (i < 0 || i > 59)
227  return 0;
228  s += 2;
229  if (!*s || *s == ',')
230  return 1; /* Okay; only date, hour and minute given. */
231  if (*s != ':')
232  return 0;
233  s++;
234  if (!digitp (s) || !digitp (s+1))
235  return 0;
236  i = atoi_2 (s);
237  if (i < 0 || i > 60)
238  return 0;
239  s += 2;
240  if (!*s || *s == ',' || spacep (s))
241  return 1; /* Okay; date, hour and minute and second given. */
242 
243  return 0; /* Unexpected delimiter. */
244 }
245 
246 
247 /* Convert a standard isotime or a human readable variant into an
248  isotime structure. The allowed formats are those described by
249  isotime_p and isotime_human_p. The function returns 0 on failure
250  or the length of the scanned string on success. */
251 static int
252 string2isotime (my_isotime_t atime, const char *string)
253 {
254  my_isotime_t dummyatime;
255 
256  if (!atime)
257  atime = dummyatime;
258 
259  atime[0] = 0;
260  if (isotime_p (string))
261  {
262  memcpy (atime, string, 15);
263  atime[15] = 0;
264  return 15;
265  }
266  if (!isotime_human_p (string))
267  return 0;
268  atime[0] = string[0];
269  atime[1] = string[1];
270  atime[2] = string[2];
271  atime[3] = string[3];
272  atime[4] = string[5];
273  atime[5] = string[6];
274  atime[6] = string[8];
275  atime[7] = string[9];
276  atime[8] = 'T';
277  memset (atime+9, '0', 6);
278  atime[15] = 0;
279  if (!spacep (string+10))
280  return 10;
281  if (spacep (string+11))
282  return 11; /* As per def, second space stops scanning. */
283  atime[9] = string[11];
284  atime[10] = string[12];
285  if (string[13] != ':')
286  return 13;
287  atime[11] = string[14];
288  atime[12] = string[15];
289  if (string[16] != ':')
290  return 16;
291  atime[13] = string[17];
292  atime[14] = string[18];
293  return 19;
294 }
295 
296 
297 /* Scan an ISO timestamp and return an Epoch based timestamp. The only
298  supported format is "yyyymmddThhmmss" delimited by white space, nul, a
299  colon or a comma. Returns (time_t)(-1) for an invalid string. */
300 #if 0 /* Not yet used. */
301 static time_t
302 isotime2epoch (const char *string)
303 {
304  int year, month, day, hour, minu, sec;
305  struct tm tmbuf;
306 
307  if (!isotime_p (string))
308  return (time_t)(-1);
309 
310  year = atoi_4 (string);
311  month = atoi_2 (string + 4);
312  day = atoi_2 (string + 6);
313  hour = atoi_2 (string + 9);
314  minu = atoi_2 (string + 11);
315  sec = atoi_2 (string + 13);
316 
317  /* Basic checks. */
318  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
319  || hour > 23 || minu > 59 || sec > 61 )
320  return (time_t)(-1);
321 
322  memset (&tmbuf, 0, sizeof tmbuf);
323  tmbuf.tm_sec = sec;
324  tmbuf.tm_min = minu;
325  tmbuf.tm_hour = hour;
326  tmbuf.tm_mday = day;
327  tmbuf.tm_mon = month-1;
328  tmbuf.tm_year = year - 1900;
329  tmbuf.tm_isdst = -1;
330  return timegm (&tmbuf);
331 }
332 #endif /* 0 */
333 
334 
335 /* Helper for jd2date. */
336 static int
337 days_per_year (int y)
338 {
339  int s ;
340 
341  s = !(y % 4);
342  if ( !(y % 100))
343  if ((y%400))
344  s = 0;
345  return s ? 366 : 365;
346 }
347 
348 
349 /* Helper for jd2date. */
350 static int
351 days_per_month (int y, int m)
352 {
353  int s;
354 
355  switch(m)
356  {
357  case 1: case 3: case 5: case 7: case 8: case 10: case 12:
358  return 31 ;
359  case 2:
360  s = !(y % 4);
361  if (!(y % 100))
362  if ((y % 400))
363  s = 0;
364  return s? 29 : 28 ;
365  case 4: case 6: case 9: case 11:
366  return 30;
367  default:
368  abort ();
369  }
370 }
371 
372 
373 /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
374  it is already noon. We do not support dates before 1582-10-15. */
375 static unsigned long
376 date2jd (int year, int month, int day)
377 {
378  unsigned long jd;
379 
380  jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
381  if (month < 3)
382  year-- ;
383  else
384  jd -= (4 * month + 23) / 10;
385 
386  jd += year / 4 - ((year / 100 + 1) *3) / 4;
387 
388  return jd ;
389 }
390 
391 
392 /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
393  the year or 0 on error. This function uses some more or less
394  arbitrary limits, most important is that days before 1582-10-15 are
395  not supported. */
396 static int
397 jd2date (unsigned long jd, int *year, int *month, int *day)
398 {
399  int y, m, d;
400  long delta;
401 
402  if (!jd)
403  return 0 ;
404  if (jd < 1721425 || jd > 2843085)
405  return 0;
406 
407  y = (jd - JD_DIFF) / 366;
408  d = m = 1;
409 
410  while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
411  y++;
412 
413  m = (delta / 31) + 1;
414  while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
415  if (++m > 12)
416  {
417  m = 1;
418  y++;
419  }
420 
421  d = delta + 1 ;
422  if (d > days_per_month (y, m))
423  {
424  d = 1;
425  m++;
426  }
427  if (m > 12)
428  {
429  m = 1;
430  y++;
431  }
432 
433  if (year)
434  *year = y;
435  if (month)
436  *month = m;
437  if (day)
438  *day = d ;
439 
440  return (jd - date2jd (y, 1, 1)) + 1;
441 }
442 
443 
444 /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
445  to about the equivalent of 62 years which should be more then
446  enough for our purposes. Returns 0 on success. */
447 static int
448 add_seconds_to_isotime (my_isotime_t atime, int nseconds)
449 {
450  int year, month, day, hour, minute, sec, ndays;
451  unsigned long jd;
452 
453  if (check_isotime (atime))
454  return 1;
455 
456  if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
457  return 1;
458 
459  year = atoi_4 (atime+0);
460  month = atoi_2 (atime+4);
461  day = atoi_2 (atime+6);
462  hour = atoi_2 (atime+9);
463  minute= atoi_2 (atime+11);
464  sec = atoi_2 (atime+13);
465 
466  /* The julian date functions don't support this. */
467  if (year < 1582
468  || (year == 1582 && month < 10)
469  || (year == 1582 && month == 10 && day < 15))
470  return 1;
471 
472  sec += nseconds;
473  minute += sec/60;
474  sec %= 60;
475  hour += minute/60;
476  minute %= 60;
477  ndays = hour/24;
478  hour %= 24;
479 
480  jd = date2jd (year, month, day) + ndays;
481  jd2date (jd, &year, &month, &day);
482 
483  if (year > 9999 || month > 12 || day > 31
484  || year < 0 || month < 1 || day < 1)
485  return 1;
486 
487  snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d",
488  year, month, day, hour, minute, sec);
489  return 0;
490 }
491 
492 
493 /* Add NDAYS to ATIME. Returns 0 on success. */
494 static int
495 add_days_to_isotime (my_isotime_t atime, int ndays)
496 {
497  int year, month, day, hour, minute, sec;
498  unsigned long jd;
499 
500  if (check_isotime (atime))
501  return 1;
502 
503  if (ndays < 0 || ndays >= 9999*366 )
504  return 1;
505 
506  year = atoi_4 (atime+0);
507  month = atoi_2 (atime+4);
508  day = atoi_2 (atime+6);
509  hour = atoi_2 (atime+9);
510  minute= atoi_2 (atime+11);
511  sec = atoi_2 (atime+13);
512 
513  /* The julian date functions don't support this. */
514  if (year < 1582
515  || (year == 1582 && month < 10)
516  || (year == 1582 && month == 10 && day < 15))
517  return 1;
518 
519  jd = date2jd (year, month, day) + ndays;
520  jd2date (jd, &year, &month, &day);
521 
522  if (year > 9999 || month > 12 || day > 31
523  || year < 0 || month < 1 || day < 1)
524  return 1;
525 
526  snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d",
527  year, month, day, hour, minute, sec);
528  return 0;
529 }
530 
531 
532 /* Add NYEARS to ATIME. Returns 0 on success. */
533 static int
534 add_years_to_isotime (my_isotime_t atime, int nyears)
535 {
536  int year, month, day, hour, minute, sec;
537  unsigned long jd;
538 
539  if (check_isotime (atime))
540  return 1;
541 
542  if (nyears < 0 || nyears >= 9999 )
543  return 1;
544 
545  year = atoi_4 (atime+0);
546  month = atoi_2 (atime+4);
547  day = atoi_2 (atime+6);
548  hour = atoi_2 (atime+9);
549  minute= atoi_2 (atime+11);
550  sec = atoi_2 (atime+13);
551 
552  /* The julian date functions don't support this. */
553  if (year < 1582
554  || (year == 1582 && month < 10)
555  || (year == 1582 && month == 10 && day < 15))
556  return 1;
557 
558  jd = date2jd (year + nyears, month, day);
559  jd2date (jd, &year, &month, &day);
560 
561  if (year > 9999 || month > 12 || day > 31
562  || year < 0 || month < 1 || day < 1)
563  return 1;
564 
565  snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d",
566  year, month, day, hour, minute, sec);
567  return 0;
568 }
569 
570 
571 
587 tree_cell *
589 {
590  tree_cell *retc;
591  my_isotime_t timebuf;
592 
593  get_current_isotime (timebuf);
594 
595  retc = alloc_typed_cell (CONST_STR);
596  retc->x.str_val = g_strdup (timebuf);
597  retc->size = strlen (timebuf);
598  return retc;
599 }
600 
601 
619 tree_cell *
621 {
622  int result = 0;
623  tree_cell *retc;
624  my_isotime_t timebuf;
625  const char *string;
626  int datalen;
627 
628  string = get_str_var_by_num (lexic, 0);
629  if (string)
630  {
631  switch (get_var_type_by_num (lexic, 0))
632  {
633  case VAR2_DATA:
634  datalen = get_var_size_by_num (lexic, 0);
635  if (datalen < ISOTIME_SIZE - 1)
636  break; /* Too short */
637  memcpy (timebuf, string, ISOTIME_SIZE - 1);
638  timebuf[ISOTIME_SIZE -1] = 0;
639  string = timebuf;
640  /* FALLTHRU */
641  case VAR2_STRING:
642  if (isotime_p (string) || isotime_human_p (string))
643  result = 1;
644  break;
645  default:
646  break;
647  }
648  }
649 
650  retc = alloc_typed_cell (CONST_INT);
651  retc->x.i_val = result;
652  return retc;
653 }
654 
655 
671 tree_cell *
673 {
674  tree_cell *retc;
675  my_isotime_t timebuf;
676  int datalen;
677  const char *string;
678 
679  *timebuf = 0;
680  string = get_str_var_by_num (lexic, 0);
681  if (!string)
682  return NULL;
683  switch (get_var_type_by_num (lexic, 0))
684  {
685  case VAR2_DATA:
686  datalen = get_var_size_by_num (lexic, 0);
687  if (datalen < ISOTIME_SIZE - 1)
688  return NULL; /* Too short */
689  memcpy (timebuf, string, ISOTIME_SIZE - 1);
690  timebuf[ISOTIME_SIZE - 1] = 0;
691  string = timebuf;
692  /* FALLTHRU */
693  case VAR2_STRING:
694  if (!string2isotime (timebuf, string))
695  return NULL;
696  break;
697  default:
698  return NULL;
699  }
700 
701  retc = alloc_typed_cell (CONST_STR);
702  retc->x.str_val = g_strdup (timebuf);
703  retc->size = strlen (timebuf);
704  return retc;
705 }
706 
707 
723 tree_cell *
725 {
726  tree_cell *retc;
727  const char *string;
728  char helpbuf[20];
729 
730  string = get_str_var_by_num (lexic, 0);
731  if (!string || get_var_size_by_num (lexic, 0) < 15 || check_isotime (string))
732  strcpy (helpbuf, "[none]");
733  else
734  snprintf (helpbuf, sizeof helpbuf,
735  "%.4s-%.2s-%.2s %.2s:%.2s:%.2s",
736  string, string+4, string+6, string+9, string+11, string+13);
737  retc = alloc_typed_cell (CONST_STR);
738  retc->x.str_val = g_strdup (helpbuf);
739  retc->size = strlen (helpbuf);
740  return retc;
741 }
742 
743 
775 tree_cell *
777 {
778  tree_cell *retc;
779  my_isotime_t timebuf;
780  const char *string;
781  int nyears, ndays, nseconds;
782 
783  string = get_str_var_by_num (lexic, 0);
784  if (!string
785  || get_var_size_by_num (lexic, 0) < ISOTIME_SIZE -1
786  || check_isotime (string))
787  return NULL;
788  memcpy (timebuf, string, ISOTIME_SIZE -1);
789  timebuf[ISOTIME_SIZE - 1] = 0;
790 
791  nyears = get_int_local_var_by_name (lexic, "years", 0);
792  ndays = get_int_local_var_by_name (lexic, "days", 0);
793  nseconds = get_int_local_var_by_name (lexic, "seconds", 0);
794 
795  if (nyears && add_years_to_isotime (timebuf, nyears))
796  return NULL;
797  if (ndays && add_days_to_isotime (timebuf, ndays))
798  return NULL;
799  if (nseconds && add_seconds_to_isotime (timebuf, nseconds))
800  return NULL;
801  /* If nothing was added, explicitly add 0 years. */
802  if (!nyears && !ndays && !nseconds && add_years_to_isotime (timebuf, 0))
803  return NULL;
804 
805  retc = alloc_typed_cell (CONST_STR);
806  retc->x.str_val = g_strdup (timebuf);
807  retc->size = strlen (timebuf);
808  return retc;
809 }
char * str_val
Definition: nasl_tree.h:113
char my_isotime_t[ISOTIME_SIZE]
Definition: nasl_isotime.c:79
tree_cell * nasl_isotime_print(lex_ctxt *lexic)
Convert an SIO time string into a better readable string.
Definition: nasl_isotime.c:724
long int get_int_local_var_by_name(lex_ctxt *, const char *, int)
Definition: nasl_var.c:1240
#define atoi_2(p)
Definition: nasl_isotime.c:90
#define JD_DIFF
Definition: nasl_isotime.c:82
union TC::@7 x
tree_cell * alloc_typed_cell(int typ)
Definition: nasl_tree.c:53
#define atoi_4(p)
Definition: nasl_isotime.c:91
tree_cell * nasl_isotime_add(lex_ctxt *lexic)
Add days or seconds to an ISO time string.
Definition: nasl_isotime.c:776
#define ISOTIME_SIZE
Definition: nasl_isotime.c:78
Definition: nasl_tree.h:105
int get_var_size_by_num(lex_ctxt *, int)
Definition: nasl_var.c:1305
#define digitp(p)
Definition: nasl_isotime.c:86
char * get_str_var_by_num(lex_ctxt *, int)
Definition: nasl_var.c:1248
long int i_val
Definition: nasl_tree.h:114
gchar * string
Protos and data structures for ISOTIME functions used by NASL scripts.
tree_cell * nasl_isotime_is_valid(lex_ctxt *lexic)
Check whether an ISO time string is valid.
Definition: nasl_isotime.c:620
tree_cell * nasl_isotime_scan(lex_ctxt *lexic)
Convert a string into an ISO time string.
Definition: nasl_isotime.c:672
#define spacep(p)
Definition: nasl_isotime.c:85
tree_cell * nasl_isotime_now(lex_ctxt *lexic)
Return the current time in ISO format.
Definition: nasl_isotime.c:588
int get_var_type_by_num(lex_ctxt *, int)
Returns NASL variable/cell type, VAR2_UNDEF if value is NULL.
Definition: nasl_var.c:1315
int size
Definition: nasl_tree.h:110