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