OpenVAS Scanner  22.7.9
nasl_isotime.c
Go to the documentation of this file.
1 /* SPDX-FileCopyrightText: 2023 Greenbone AG
2  * SPDX-FileCopyrightText: 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 /* This code is based on code from GnuPG 2.x, file common/gettime.c,
8  commit id 76055d4. The copyright was LGPLv3+ or GPLv2+; we chose
9  GPLv2+. The only author of that code is Werner Koch; who assigned
10  the copyright to the FSF. */
11 
34 #include "nasl_isotime.h"
35 
36 #include "nasl_debug.h"
37 #include "nasl_global_ctxt.h"
38 #include "nasl_lex_ctxt.h"
39 #include "nasl_tree.h"
40 #include "nasl_var.h"
41 
42 #include <ctype.h>
43 #include <glib.h>
44 #include <glib/gstdio.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50 
51 #undef G_LOG_DOMAIN
52 
55 #define G_LOG_DOMAIN "lib nasl"
56 
57 #ifndef DIM
58 #define DIM(v) (sizeof (v) / sizeof ((v)[0]))
59 #define DIMof(type, member) DIM (((type *) 0)->member)
60 #endif
61 
62 /* The type used to represent the time here is a string with a fixed
63  length. */
64 #define ISOTIME_SIZE 16
65 typedef char my_isotime_t[ISOTIME_SIZE];
66 
67 /* Correction used to map to real Julian days. */
68 #define JD_DIFF 1721060L
69 
70 /* Useful helper macros to avoid problems with locales. */
71 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
72 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
73 
74 /* The atoi macros assume that the buffer has only valid digits. */
75 #define atoi_1(p) (*(p) - '0')
76 #define atoi_2(p) ((atoi_1 (p) * 10) + atoi_1 ((p) + 1))
77 #define atoi_4(p) ((atoi_2 (p) * 100) + atoi_2 ((p) + 2))
78 
79 /* Convert an Epoch time to an ISO timestamp. */
80 static void
81 epoch2isotime (my_isotime_t timebuf, time_t atime)
82 {
83  if (atime == (time_t) (-1))
84  *timebuf = 0;
85  else
86  {
87  struct tm tp;
88 
89  gmtime_r (&atime, &tp);
90  if (snprintf (timebuf, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d",
91  1900 + tp.tm_year, tp.tm_mon + 1, tp.tm_mday, tp.tm_hour,
92  tp.tm_min, tp.tm_sec)
93  < 0)
94  {
95  *timebuf = '\0';
96  return;
97  }
98  }
99 }
100 
101 /* Return the current time in ISO format. */
102 static void
104 {
105  epoch2isotime (timebuf, time (NULL));
106 }
107 
108 /* Check that the 15 bytes in ATIME represent a valid ISO timestamp.
109  Returns 0 if ATIME has a valid format. Note that this function
110  does not expect a string but a check just the plain 15 bytes of the
111  the buffer without looking at the string terminator. */
112 static int
114 {
115  int i;
116  const char *s;
117 
118  if (!*atime)
119  return 1;
120 
121  for (s = atime, i = 0; i < 8; i++, s++)
122  if (!digitp (s))
123  return 1;
124  if (*s != 'T')
125  return 1;
126  for (s++, i = 9; i < 15; i++, s++)
127  if (!digitp (s))
128  return 1;
129  return 0;
130 }
131 
132 /* Return true if STRING holds an isotime string. The expected format is
133  yyyymmddThhmmss
134  optionally terminated by white space, comma, or a colon.
135  */
136 static int
137 isotime_p (const char *string)
138 {
139  const char *s;
140  int i;
141 
142  if (!*string)
143  return 0;
144  for (s = string, i = 0; i < 8; i++, s++)
145  if (!digitp (s))
146  return 0;
147  if (*s != 'T')
148  return 0;
149  for (s++, i = 9; i < 15; i++, s++)
150  if (!digitp (s))
151  return 0;
152  if (!(!*s || (isascii (*s) && isspace (*s)) || *s == ':' || *s == ','))
153  return 0; /* Wrong delimiter. */
154 
155  return 1;
156 }
157 
158 /* Scan a string and return true if the string represents the human
159  readable format of an ISO time. This format is:
160  yyyy-mm-dd[ hh[:mm[:ss]]]
161  Scanning stops at the second space or at a comma. */
162 static int
163 isotime_human_p (const char *string)
164 {
165  const char *s;
166  int i;
167 
168  if (!*string)
169  return 0;
170  for (s = string, i = 0; i < 4; i++, s++)
171  if (!digitp (s))
172  return 0;
173  if (*s != '-')
174  return 0;
175  s++;
176  if (!digitp (s) || !digitp (s + 1) || s[2] != '-')
177  return 0;
178  i = atoi_2 (s);
179  if (i < 1 || i > 12)
180  return 0;
181  s += 3;
182  if (!digitp (s) || !digitp (s + 1))
183  return 0;
184  i = atoi_2 (s);
185  if (i < 1 || i > 31)
186  return 0;
187  s += 2;
188  if (!*s || *s == ',')
189  return 1; /* Okay; only date given. */
190  if (!spacep (s))
191  return 0;
192  s++;
193  if (spacep (s))
194  return 1; /* Okay, second space stops scanning. */
195  if (!digitp (s) || !digitp (s + 1))
196  return 0;
197  i = atoi_2 (s);
198  if (i < 0 || i > 23)
199  return 0;
200  s += 2;
201  if (!*s || *s == ',')
202  return 1; /* Okay; only date and hour given. */
203  if (*s != ':')
204  return 0;
205  s++;
206  if (!digitp (s) || !digitp (s + 1))
207  return 0;
208  i = atoi_2 (s);
209  if (i < 0 || i > 59)
210  return 0;
211  s += 2;
212  if (!*s || *s == ',')
213  return 1; /* Okay; only date, hour and minute given. */
214  if (*s != ':')
215  return 0;
216  s++;
217  if (!digitp (s) || !digitp (s + 1))
218  return 0;
219  i = atoi_2 (s);
220  if (i < 0 || i > 60)
221  return 0;
222  s += 2;
223  if (!*s || *s == ',' || spacep (s))
224  return 1; /* Okay; date, hour and minute and second given. */
225 
226  return 0; /* Unexpected delimiter. */
227 }
228 
229 /* Convert a standard isotime or a human readable variant into an
230  isotime structure. The allowed formats are those described by
231  isotime_p and isotime_human_p. The function returns 0 on failure
232  or the length of the scanned string on success. */
233 static int
234 string2isotime (my_isotime_t atime, const char *string)
235 {
236  my_isotime_t dummyatime;
237 
238  if (!atime)
239  atime = dummyatime;
240 
241  memset (atime, '\0', sizeof (my_isotime_t));
242  atime[0] = 0;
243  if (isotime_p (string))
244  {
245  memcpy (atime, string, 15);
246  atime[15] = 0;
247  return 15;
248  }
249  if (!isotime_human_p (string))
250  return 0;
251  atime[0] = string[0];
252  atime[1] = string[1];
253  atime[2] = string[2];
254  atime[3] = string[3];
255  atime[4] = string[5];
256  atime[5] = string[6];
257  atime[6] = string[8];
258  atime[7] = string[9];
259  atime[8] = 'T';
260  if (!spacep (string + 10))
261  return 10;
262  if (spacep (string + 11))
263  return 11; /* As per def, second space stops scanning. */
264  atime[9] = string[11];
265  atime[10] = string[12];
266  if (string[13] != ':')
267  {
268  atime[11] = '0';
269  atime[12] = '0';
270  atime[13] = '0';
271  atime[14] = '0';
272  return 13;
273  }
274  atime[11] = string[14];
275  atime[12] = string[15];
276  if (string[16] != ':')
277  {
278  atime[13] = '0';
279  atime[14] = '0';
280  return 16;
281  }
282  atime[13] = string[17];
283  atime[14] = string[18];
284  return 19;
285 }
286 
287 /* Helper for jd2date. */
288 static int
290 {
291  int s;
292 
293  s = !(y % 4);
294  if (!(y % 100))
295  if ((y % 400))
296  s = 0;
297  return s ? 366 : 365;
298 }
299 
300 /* Helper for jd2date. */
301 static int
302 days_per_month (int y, int m)
303 {
304  int s;
305 
306  switch (m)
307  {
308  case 1:
309  case 3:
310  case 5:
311  case 7:
312  case 8:
313  case 10:
314  case 12:
315  return 31;
316  case 2:
317  s = !(y % 4);
318  if (!(y % 100))
319  if ((y % 400))
320  s = 0;
321  return s ? 29 : 28;
322  case 4:
323  case 6:
324  case 9:
325  case 11:
326  return 30;
327  default:
328  abort ();
329  }
330 }
331 
332 /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
333  it is already noon. We do not support dates before 1582-10-15. */
334 static unsigned long
335 date2jd (int year, int month, int day)
336 {
337  unsigned long jd;
338 
339  jd = 365L * year + 31 * (month - 1) + day + JD_DIFF;
340  if (month < 3)
341  year--;
342  else
343  jd -= (4 * month + 23) / 10;
344 
345  jd += year / 4 - ((year / 100 + 1) * 3) / 4;
346 
347  return jd;
348 }
349 
350 /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
351  the year or 0 on error. This function uses some more or less
352  arbitrary limits, most important is that days before 1582-10-15 are
353  not supported. */
354 static int
355 jd2date (unsigned long jd, int *year, int *month, int *day)
356 {
357  int y, m, d;
358  long delta;
359 
360  if (!jd)
361  return 0;
362  if (jd < 1721425 || jd > 2843085)
363  return 0;
364 
365  y = (jd - JD_DIFF) / 366;
366  d = m = 1;
367 
368  while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
369  y++;
370 
371  m = (delta / 31) + 1;
372  while ((delta = jd - date2jd (y, m, d)) > days_per_month (y, m))
373  if (++m > 12)
374  {
375  m = 1;
376  y++;
377  }
378 
379  d = delta + 1;
380  if (d > days_per_month (y, m))
381  {
382  d = 1;
383  m++;
384  }
385  if (m > 12)
386  {
387  m = 1;
388  y++;
389  }
390 
391  if (year)
392  *year = y;
393  if (month)
394  *month = m;
395  if (day)
396  *day = d;
397 
398  return (jd - date2jd (y, 1, 1)) + 1;
399 }
400 
401 /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
402  to about the equivalent of 62 years which should be more then
403  enough for our purposes. Returns 0 on success. */
404 static int
406 {
407  int year, month, day, hour, minute, sec, ndays;
408  unsigned long jd;
409 
410  if (check_isotime (atime))
411  return 1;
412 
413  if (nseconds < 0 || nseconds >= (0x7fffffff - 61))
414  return 1;
415 
416  year = atoi_4 (atime + 0);
417  month = atoi_2 (atime + 4);
418  day = atoi_2 (atime + 6);
419  hour = atoi_2 (atime + 9);
420  minute = atoi_2 (atime + 11);
421  sec = atoi_2 (atime + 13);
422 
423  /* The julian date functions don't support this. */
424  if (year < 1582 || (year == 1582 && month < 10)
425  || (year == 1582 && month == 10 && day < 15))
426  return 1;
427 
428  sec += nseconds;
429  minute += sec / 60;
430  sec %= 60;
431  hour += minute / 60;
432  minute %= 60;
433  ndays = hour / 24;
434  hour %= 24;
435 
436  jd = date2jd (year, month, day) + ndays;
437  jd2date (jd, &year, &month, &day);
438 
439  if (year > 9999 || month > 12 || day > 31 || year < 0 || month < 1 || day < 1)
440  return 1;
441 
442  if (snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d", year, month,
443  day, hour, minute, sec)
444  < 0)
445  return 1;
446 
447  return 0;
448 }
449 
450 /* Add NDAYS to ATIME. Returns 0 on success. */
451 static int
453 {
454  int year, month, day, hour, minute, sec;
455  unsigned long jd;
456 
457  if (check_isotime (atime))
458  return 1;
459 
460  if (ndays < 0 || ndays >= 9999 * 366)
461  return 1;
462 
463  year = atoi_4 (atime + 0);
464  month = atoi_2 (atime + 4);
465  day = atoi_2 (atime + 6);
466  hour = atoi_2 (atime + 9);
467  minute = atoi_2 (atime + 11);
468  sec = atoi_2 (atime + 13);
469 
470  /* The julian date functions don't support this. */
471  if (year < 1582 || (year == 1582 && month < 10)
472  || (year == 1582 && month == 10 && day < 15))
473  return 1;
474 
475  jd = date2jd (year, month, day) + ndays;
476  jd2date (jd, &year, &month, &day);
477 
478  if (year > 9999 || month > 12 || day > 31 || year < 0 || month < 1 || day < 1)
479  return 1;
480 
481  if (snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d", year, month,
482  day, hour, minute, sec)
483  < 0)
484  return 1;
485  return 0;
486 }
487 
488 /* Add NYEARS to ATIME. Returns 0 on success. */
489 static int
491 {
492  int year, month, day, hour, minute, sec;
493  unsigned long jd;
494 
495  if (check_isotime (atime))
496  return 1;
497 
498  if (nyears < 0 || nyears >= 9999)
499  return 1;
500 
501  year = atoi_4 (atime + 0);
502  month = atoi_2 (atime + 4);
503  day = atoi_2 (atime + 6);
504  hour = atoi_2 (atime + 9);
505  minute = atoi_2 (atime + 11);
506  sec = atoi_2 (atime + 13);
507 
508  /* The julian date functions don't support this. */
509  if (year < 1582 || (year == 1582 && month < 10)
510  || (year == 1582 && month == 10 && day < 15))
511  return 1;
512 
513  jd = date2jd (year + nyears, month, day);
514  jd2date (jd, &year, &month, &day);
515 
516  if (year > 9999 || month > 12 || day > 31 || year < 0 || month < 1 || day < 1)
517  return 1;
518 
519  if (snprintf (atime, ISOTIME_SIZE, "%04d%02d%02dT%02d%02d%02d", year, month,
520  day, hour, minute, sec)
521  < 0)
522  return 1;
523 
524  return 0;
525 }
526 
542 tree_cell *
544 {
545  tree_cell *retc;
546  my_isotime_t timebuf;
547 
548  (void) lexic;
549  get_current_isotime (timebuf);
550 
551  retc = alloc_typed_cell (CONST_STR);
552  retc->x.str_val = g_strdup (timebuf);
553  retc->size = strlen (timebuf);
554  return retc;
555 }
556 
574 tree_cell *
576 {
577  int result = 0;
578  tree_cell *retc;
579  my_isotime_t timebuf;
580  const char *string;
581  int datalen;
582 
583  string = get_str_var_by_num (lexic, 0);
584  if (string)
585  {
586  switch (get_var_type_by_num (lexic, 0))
587  {
588  case VAR2_DATA:
589  datalen = get_var_size_by_num (lexic, 0);
590  if (datalen < ISOTIME_SIZE - 1)
591  break; /* Too short */
592  memcpy (timebuf, string, ISOTIME_SIZE - 1);
593  timebuf[ISOTIME_SIZE - 1] = 0;
594  string = timebuf;
595  /* FALLTHRU */
596  case VAR2_STRING:
597  if (isotime_p (string) || isotime_human_p (string))
598  result = 1;
599  break;
600  default:
601  break;
602  }
603  }
604 
605  retc = alloc_typed_cell (CONST_INT);
606  retc->x.i_val = result;
607  return retc;
608 }
609 
625 tree_cell *
627 {
628  tree_cell *retc;
629  my_isotime_t timebuf;
630  int datalen;
631  const char *string;
632 
633  *timebuf = 0;
634  string = get_str_var_by_num (lexic, 0);
635  if (!string)
636  return NULL;
637  switch (get_var_type_by_num (lexic, 0))
638  {
639  case VAR2_DATA:
640  datalen = get_var_size_by_num (lexic, 0);
641  if (datalen < ISOTIME_SIZE - 1)
642  return NULL; /* Too short */
643  memcpy (timebuf, string, ISOTIME_SIZE - 1);
644  timebuf[ISOTIME_SIZE - 1] = 0;
645  string = timebuf;
646  /* FALLTHRU */
647  case VAR2_STRING:
648  if (!string2isotime (timebuf, string))
649  return NULL;
650  break;
651  default:
652  return NULL;
653  }
654 
655  retc = alloc_typed_cell (CONST_STR);
656  retc->x.str_val = g_strdup (timebuf);
657  retc->size = strlen (timebuf);
658  return retc;
659 }
660 
676 tree_cell *
678 {
679  tree_cell *retc;
680  const char *string;
681  char helpbuf[20];
682 
683  string = get_str_var_by_num (lexic, 0);
684  if (!string || get_var_size_by_num (lexic, 0) < 15 || check_isotime (string))
685  strcpy (helpbuf, "[none]");
686  else
687  snprintf (helpbuf, sizeof helpbuf, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s", string,
688  string + 4, string + 6, string + 9, string + 11, string + 13);
689  retc = alloc_typed_cell (CONST_STR);
690  retc->x.str_val = g_strdup (helpbuf);
691  retc->size = strlen (helpbuf);
692  return retc;
693 }
694 
726 tree_cell *
728 {
729  tree_cell *retc;
730  my_isotime_t timebuf;
731  const char *string;
732  int nyears, ndays, nseconds;
733 
734  string = get_str_var_by_num (lexic, 0);
735  if (!string || get_var_size_by_num (lexic, 0) < ISOTIME_SIZE - 1
736  || check_isotime (string))
737  return NULL;
738  memcpy (timebuf, string, ISOTIME_SIZE - 1);
739  timebuf[ISOTIME_SIZE - 1] = 0;
740 
741  nyears = get_int_var_by_name (lexic, "years", 0);
742  ndays = get_int_var_by_name (lexic, "days", 0);
743  nseconds = get_int_var_by_name (lexic, "seconds", 0);
744 
745  if (nyears && add_years_to_isotime (timebuf, nyears))
746  return NULL;
747  if (ndays && add_days_to_isotime (timebuf, ndays))
748  return NULL;
749  if (nseconds && add_seconds_to_isotime (timebuf, nseconds))
750  return NULL;
751  /* If nothing was added, explicitly add 0 years. */
752  if (!nyears && !ndays && !nseconds && add_years_to_isotime (timebuf, 0))
753  return NULL;
754 
755  retc = alloc_typed_cell (CONST_STR);
756  retc->x.str_val = g_strdup (timebuf);
757  retc->size = strlen (timebuf);
758  return retc;
759 }
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:575
date2jd
static unsigned long date2jd(int year, int month, int day)
Definition: nasl_isotime.c:335
TC::str_val
char * str_val
Definition: nasl_tree.h:103
days_per_month
static int days_per_month(int y, int m)
Definition: nasl_isotime.c:302
string2isotime
static int string2isotime(my_isotime_t atime, const char *string)
Definition: nasl_isotime.c:234
CONST_STR
@ CONST_STR
Definition: nasl_tree.h:80
nasl_isotime.h
Protos and data structures for ISOTIME functions used by NASL scripts.
TC::x
union TC::@5 x
isotime_p
static int isotime_p(const char *string)
Definition: nasl_isotime.c:137
check_isotime
static int check_isotime(const my_isotime_t atime)
Definition: nasl_isotime.c:113
VAR2_STRING
@ VAR2_STRING
Definition: nasl_var.h:17
VAR2_DATA
@ VAR2_DATA
Definition: nasl_var.h:18
nasl_isotime_add
tree_cell * nasl_isotime_add(lex_ctxt *lexic)
Add days or seconds to an ISO time string.
Definition: nasl_isotime.c:727
my_isotime_t
char my_isotime_t[ISOTIME_SIZE]
Definition: nasl_isotime.c:65
nasl_debug.h
add_days_to_isotime
static int add_days_to_isotime(my_isotime_t atime, int ndays)
Definition: nasl_isotime.c:452
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:677
TC::size
int size
Definition: nasl_tree.h:99
nasl_lex_ctxt.h
atoi_2
#define atoi_2(p)
Definition: nasl_isotime.c:76
JD_DIFF
#define JD_DIFF
Definition: nasl_isotime.c:68
get_int_var_by_name
long int get_int_var_by_name(lex_ctxt *, const char *, int)
Definition: nasl_var.c:1104
ISOTIME_SIZE
#define ISOTIME_SIZE
Definition: nasl_isotime.c:64
add_seconds_to_isotime
static int add_seconds_to_isotime(my_isotime_t atime, int nseconds)
Definition: nasl_isotime.c:405
digitp
#define digitp(p)
Definition: nasl_isotime.c:72
get_str_var_by_num
char * get_str_var_by_num(lex_ctxt *, int)
Definition: nasl_var.c:1111
atoi_4
#define atoi_4(p)
Definition: nasl_isotime.c:77
days_per_year
static int days_per_year(int y)
Definition: nasl_isotime.c:289
TC
Definition: nasl_tree.h:94
add_years_to_isotime
static int add_years_to_isotime(my_isotime_t atime, int nyears)
Definition: nasl_isotime.c:490
struct_lex_ctxt
Definition: nasl_lex_ctxt.h:23
nasl_var.h
get_current_isotime
static void get_current_isotime(my_isotime_t timebuf)
Definition: nasl_isotime.c:103
epoch2isotime
static void epoch2isotime(my_isotime_t timebuf, time_t atime)
Definition: nasl_isotime.c:81
nasl_global_ctxt.h
CONST_INT
@ CONST_INT
Definition: nasl_tree.h:79
get_var_size_by_num
int get_var_size_by_num(lex_ctxt *, int)
Definition: nasl_var.c:1145
isotime_human_p
static int isotime_human_p(const char *string)
Definition: nasl_isotime.c:163
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:1155
nasl_isotime_scan
tree_cell * nasl_isotime_scan(lex_ctxt *lexic)
Convert a string into an ISO time string.
Definition: nasl_isotime.c:626
jd2date
static int jd2date(unsigned long jd, int *year, int *month, int *day)
Definition: nasl_isotime.c:355
alloc_typed_cell
tree_cell * alloc_typed_cell(int typ)
Definition: nasl_tree.c:28
spacep
#define spacep(p)
Definition: nasl_isotime.c:71
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:543
TC::i_val
long int i_val
Definition: nasl_tree.h:104