OpenVAS Scanner 23.32.3
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
33
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
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
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. */
80static void
81epoch2isotime (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. */
102static 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. */
112static 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 */
136static int
137isotime_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. */
162static int
163isotime_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. */
233static int
234string2isotime (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. */
288static 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. */
301static int
302days_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. */
334static unsigned long
335date2jd (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. */
354static int
355jd2date (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. */
404static 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. */
451static 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. */
489static 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
542tree_cell *
544{
545 tree_cell *retc;
546 my_isotime_t timebuf;
547
548 (void) lexic;
549 get_current_isotime (timebuf);
550
552 retc->x.str_val = g_strdup (timebuf);
553 retc->size = strlen (timebuf);
554 return retc;
555}
556
574tree_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
606 retc->x.i_val = result;
607 return retc;
608}
609
625tree_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
656 retc->x.str_val = g_strdup (timebuf);
657 retc->size = strlen (timebuf);
658 return retc;
659}
660
676tree_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);
690 retc->x.str_val = g_strdup (helpbuf);
691 retc->size = strlen (helpbuf);
692 return retc;
693}
694
726tree_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
756 retc->x.str_val = g_strdup (timebuf);
757 retc->size = strlen (timebuf);
758 return retc;
759}
static int days_per_month(int y, int m)
#define JD_DIFF
#define ISOTIME_SIZE
static int check_isotime(const my_isotime_t atime)
static unsigned long date2jd(int year, int month, int day)
tree_cell * nasl_isotime_add(lex_ctxt *lexic)
Add days or seconds to an ISO time string.
static int add_seconds_to_isotime(my_isotime_t atime, int nseconds)
static int add_days_to_isotime(my_isotime_t atime, int ndays)
#define spacep(p)
tree_cell * nasl_isotime_is_valid(lex_ctxt *lexic)
Check whether an ISO time string is valid.
char my_isotime_t[ISOTIME_SIZE]
tree_cell * nasl_isotime_print(lex_ctxt *lexic)
Convert an SIO time string into a better readable string.
#define digitp(p)
static int isotime_p(const char *string)
tree_cell * nasl_isotime_now(lex_ctxt *lexic)
Return the current time in ISO format.
static int string2isotime(my_isotime_t atime, const char *string)
static int isotime_human_p(const char *string)
static void epoch2isotime(my_isotime_t timebuf, time_t atime)
static int add_years_to_isotime(my_isotime_t atime, int nyears)
tree_cell * nasl_isotime_scan(lex_ctxt *lexic)
Convert a string into an ISO time string.
#define atoi_4(p)
#define atoi_2(p)
static int jd2date(unsigned long jd, int *year, int *month, int *day)
static int days_per_year(int y)
static void get_current_isotime(my_isotime_t timebuf)
Protos and data structures for ISOTIME functions used by NASL scripts.
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
struct struct_lex_ctxt lex_ctxt
int get_var_size_by_num(lex_ctxt *, int)
Definition nasl_var.c:1145
char * get_str_var_by_num(lex_ctxt *, int)
Definition nasl_var.c:1108
long int get_int_var_by_name(lex_ctxt *, const char *, int)
Definition nasl_var.c:1101
tree_cell * alloc_typed_cell(int typ)
Definition nasl_tree.c:25
@ CONST_STR
Definition nasl_tree.h:80
@ CONST_INT
Definition nasl_tree.h:79
struct TC tree_cell
@ VAR2_STRING
Definition nasl_var.h:17
@ VAR2_DATA
Definition nasl_var.h:18
int size
Definition nasl_tree.h:99
long int i_val
Definition nasl_tree.h:104
union TC::@332262321161220155002104006201360276211317150140 x
char * str_val
Definition nasl_tree.h:103
Define a string struct for storing the response.