Coverage Report

Created: 2026-10-08 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/gettime.c
Line
Count
Source
1
/* gettime.c - Wrapper for time functions
2
 * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * This file is free software; you can redistribute it and/or modify
7
 * it under the terms of either
8
 *
9
 *   - the GNU Lesser General Public License as published by the Free
10
 *     Software Foundation; either version 3 of the License, or (at
11
 *     your option) any later version.
12
 *
13
 * or
14
 *
15
 *   - the GNU General Public License as published by the Free
16
 *     Software Foundation; either version 2 of the License, or (at
17
 *     your option) any later version.
18
 *
19
 * or both in parallel, as here.
20
 *
21
 * This file is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28
 */
29
30
#include <config.h>
31
#include <stdlib.h>
32
#include <time.h>
33
#include <ctype.h>
34
#ifdef HAVE_LOCALE_H
35
#include <locale.h>
36
#endif
37
#ifdef HAVE_LANGINFO_H
38
#include <langinfo.h>
39
#endif
40
#ifdef HAVE_W32_SYSTEM
41
# define WIN32_LEAN_AND_MEAN
42
# include <windows.h>
43
#endif /*!HAVE_W32_SYSTEM*/
44
#include <stdint.h>    /* We use uint64_t.  */
45
46
#include "util.h"
47
#include "i18n.h"
48
#include "gettime.h"
49
50
#ifdef HAVE_W32_SYSTEM
51
#include <windows.h>
52
#endif
53
54
#ifdef HAVE_UNSIGNED_TIME_T
55
# define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
56
#else
57
  /* Error or 32 bit time_t and value after 2038-01-19.  */
58
8.90k
# define IS_INVALID_TIME_T(a) ((a) < 0)
59
#endif
60
61
62
static unsigned long timewarp;
63
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
64
65
/* Correction used to map to real Julian days. */
66
0
#define JD_DIFF 1721060L
67
68
69
/* Fill BUFFER with the date and time given by TP in the locale
70
 * specific standard format.  BUFSIZE gives the allocated length of
71
 * the buffer to be passed to strftime.
72
 *
73
 * Note: gcc -Wformat-noliteral would complain here.  Thus we disable
74
 * it for this function.  */
75
#if defined(HAVE_STRFTIME) && defined(HAVE_NL_LANGINFO)
76
# if GPGRT_HAVE_PRAGMA_GCC_PUSH
77
#  pragma GCC diagnostic push
78
#  pragma GCC diagnostic ignored "-Wformat-nonliteral"
79
# endif
80
static void
81
format_time_nl_langinfo (char *buffer, size_t bufsize, struct tm *tp)
82
8.90k
{
83
8.90k
  static char fmtinit;
84
8.90k
  static char fmt[80];
85
86
8.90k
  if (!fmtinit)
87
1
    {
88
1
      mem2str (fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3);
89
1
      if (!strstr (fmt, "%Z"))
90
1
        strcat (fmt, " %Z");
91
1
      fmtinit = 1;
92
1
    }
93
94
8.90k
  if (!bufsize)
95
0
    *buffer = 0;
96
8.90k
  else
97
8.90k
    strftime (buffer, bufsize-1, fmt, tp);
98
8.90k
}
99
# if GPGRT_HAVE_PRAGMA_GCC_PUSH
100
#  pragma GCC diagnostic pop
101
# endif
102
#endif /* HAVE_STRFTIME && HAVE_NL_LANGINFO */
103
104
105
/*
106
  timegm() is a GNU function that might not be available everywhere.
107
  It's basically the inverse of gmtime() - you give it a struct tm,
108
  and get back a time_t.  It differs from mktime() in that it handles
109
  the case where the struct tm is UTC and the local environment isn't.
110
111
  Note, that this replacement implementation might not be thread-safe!
112
113
  Some BSDs don't handle the putenv("foo") case properly, so we use
114
  unsetenv if the platform has it to remove environment variables.
115
*/
116
#ifndef HAVE_TIMEGM
117
time_t
118
timegm (struct tm *tm)
119
{
120
#ifdef HAVE_W32_SYSTEM
121
  uint64_t val = timegm_u64 (tm);
122
  if (val == (uint64_t)(-1))
123
    return (time_t)(-1);
124
  return (time_t)val;
125
#else /* (Non thread safe implementation!) */
126
127
  time_t answer;
128
  char *zone;
129
130
  zone=getenv("TZ");
131
  putenv("TZ=UTC");
132
  tzset();
133
  answer=mktime(tm);
134
  if(zone)
135
    {
136
      static char *old_zone;
137
138
      if (!old_zone)
139
        {
140
          old_zone = malloc(3+strlen(zone)+1);
141
          if (old_zone)
142
            {
143
              strcpy(old_zone,"TZ=");
144
              strcat(old_zone,zone);
145
            }
146
  }
147
      if (old_zone)
148
        putenv (old_zone);
149
    }
150
  else
151
    gnupg_unsetenv("TZ");
152
153
  tzset();
154
  return answer;
155
#endif
156
}
157
#endif /*!HAVE_TIMEGM*/
158
159
160
/* Version of the GNU timegm which returns an unsigned 64 bit integer
161
 * instead of the usually signed time_t.  On error (uint64_t)(-1) is
162
 * returned.  This function is mostly here because on 32 bit Windows
163
 * we have an internal API to get the system time even after
164
 * 2023-01-19.  For 32 bit Unix we need to suffer from the too short
165
 * time_t and no system function to construct the time from a tm.  */
166
uint64_t
167
timegm_u64 (struct tm *tm)
168
0
{
169
#ifdef HAVE_W32_SYSTEM
170
  /* This one is thread safe.  */
171
  SYSTEMTIME st;
172
  FILETIME ft;
173
  unsigned long long cnsecs;
174
175
  st.wYear   = tm->tm_year + 1900;
176
  st.wMonth  = tm->tm_mon  + 1;
177
  st.wDay    = tm->tm_mday;
178
  st.wHour   = tm->tm_hour;
179
  st.wMinute = tm->tm_min;
180
  st.wSecond = tm->tm_sec;
181
  st.wMilliseconds = 0; /* Not available.  */
182
  st.wDayOfWeek = 0;    /* Ignored.  */
183
184
  /* System time is UTC thus the conversion is pretty easy.  */
185
  if (!SystemTimeToFileTime (&st, &ft))
186
    {
187
      gpg_err_set_errno (EINVAL);
188
      return (uint64_t)(-1);
189
    }
190
191
  cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
192
            | ft.dwLowDateTime);
193
  cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
194
  return (uint64_t)(cnsecs / 10000000ULL);
195
196
#else /*Unix*/
197
198
0
  time_t t = timegm (tm);
199
0
  if (t == (time_t)(-1))
200
0
    return (uint64_t)(-1);
201
0
  if ((int64_t)t < 0)
202
0
    return (uint64_t)(-1);
203
0
  return (uint64_t)t;
204
205
0
#endif /*Unix*/
206
0
}
207
208
209
/* Wrapper for the time(3).  We use this here so we can fake the time
210
   for tests */
211
time_t
212
gnupg_get_time (void)
213
48.3k
{
214
48.3k
  time_t current = time (NULL);
215
216
48.3k
  if (current == (time_t)(-1))
217
48.3k
    log_fatal ("time() failed\n");
218
219
48.3k
  if (timemode == NORMAL)
220
48.3k
    return current;
221
0
  else if (timemode == FROZEN)
222
0
    return timewarp;
223
0
  else if (timemode == FUTURE)
224
0
    return current + timewarp;
225
0
  else
226
0
    return current - timewarp;
227
48.3k
}
228
229
230
/* Wrapper around gmtime_r.
231
232
   On systems without gmtime_r this implementation works within gnupg
233
   because we use only one thread a time.  FIXME: An independent
234
   library may use gmtime in one of its own thread (or via
235
   npth_enter/npth_leave) - in this case we run into a problem.  The
236
   solution would be to use a mutex here.  */
237
struct tm *
238
gnupg_gmtime (const time_t *timep, struct tm *result)
239
0
{
240
0
#ifdef HAVE_GMTIME_R
241
0
  return gmtime_r (timep, result);
242
#else
243
  struct tm *tp;
244
245
  tp = gmtime (timep);
246
  if (tp)
247
    memcpy (result, tp, sizeof *result);
248
  return tp;
249
#endif
250
0
}
251
252
253
/* Return the current time (possibly faked) in ISO format. */
254
void
255
gnupg_get_isotime (gnupg_isotime_t timebuf)
256
0
{
257
0
  time_t atime = gnupg_get_time ();
258
0
  struct tm *tp;
259
0
  struct tm tmbuf;
260
261
0
  tp = gnupg_gmtime (&atime, &tmbuf);
262
0
  if (!tp)
263
0
    *timebuf = 0;
264
0
  else
265
0
    snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
266
0
              1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
267
0
              tp->tm_hour, tp->tm_min, tp->tm_sec);
268
0
}
269
270
271
/* Set the time to NEWTIME so that gnupg_get_time returns a time
272
   starting with this one.  With FREEZE set to 1 the returned time
273
   will never change.  Just for completeness, a value of (time_t)-1
274
   for NEWTIME gets you back to reality.  Note that this is obviously
275
   not thread-safe but this is not required. */
276
void
277
gnupg_set_time (time_t newtime, int freeze)
278
0
{
279
0
  time_t current = time (NULL);
280
281
0
  if ( newtime == (time_t)-1 || current == newtime)
282
0
    {
283
0
      timemode = NORMAL;
284
0
      timewarp = 0;
285
0
    }
286
0
  else if (freeze)
287
0
    {
288
0
      timemode = FROZEN;
289
0
      timewarp = newtime == (time_t)-1 ? current : newtime;
290
0
    }
291
0
  else if (newtime > current)
292
0
    {
293
0
      timemode = FUTURE;
294
0
      timewarp = newtime - current;
295
0
    }
296
0
  else
297
0
    {
298
0
      timemode = PAST;
299
0
      timewarp = current - newtime;
300
0
    }
301
0
}
302
303
/* Returns true when we are in timewarp mode */
304
int
305
gnupg_faked_time_p (void)
306
0
{
307
0
  return timemode;
308
0
}
309
310
311
/* This function is used by gpg because OpenPGP defines the timestamp
312
   as an unsigned 32 bit value. */
313
u32
314
make_timestamp (void)
315
48.3k
{
316
48.3k
  time_t t = gnupg_get_time ();
317
48.3k
  return (u32)t;
318
48.3k
}
319
320
321
/* Specialized version of atoi which returns an u32 instead of an int
322
 * and caps the result at 2^32-2.  Leading white space is skipped,
323
 * scanning stops at at the first non-convertable byte.  Note that we
324
 * do not cap at 2^32-1 because that value is often used as error
325
 * return. */
326
u32
327
scan_secondsstr (const char *string)
328
0
{
329
0
  uint64_t value = 0;
330
331
0
  while (*string == ' ' || *string == '\t')
332
0
    string++;
333
0
  for (; *string >= '0' && *string <= '9'; string++)
334
0
    {
335
0
      value *= 10;
336
0
      value += atoi_1 (string);
337
0
      if (value >= (u32)(-1))
338
0
        return (u32)(-1) - 1;
339
0
    }
340
0
  return (u32)value;
341
0
}
342
343
344
/****************
345
 * Scan a date string and return a timestamp.
346
 * The only supported format is "yyyy-mm-dd"
347
 * Returns 0 for an invalid date.
348
 */
349
u32
350
scan_isodatestr( const char *string )
351
0
{
352
0
    int year, month, day;
353
0
    struct tm tmbuf;
354
0
    time_t stamp;
355
0
    int i;
356
357
0
    if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
358
0
  return 0;
359
0
    for( i=0; i < 4; i++ )
360
0
  if( !digitp (string+i) )
361
0
      return 0;
362
0
    if( !digitp (string+5) || !digitp(string+6) )
363
0
  return 0;
364
0
    if( !digitp(string+8) || !digitp(string+9) )
365
0
  return 0;
366
0
    year = atoi(string);
367
0
    month = atoi(string+5);
368
0
    day = atoi(string+8);
369
    /* some basic checks */
370
0
    if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
371
0
  return 0;
372
0
    memset( &tmbuf, 0, sizeof tmbuf );
373
0
    tmbuf.tm_mday = day;
374
0
    tmbuf.tm_mon = month-1;
375
0
    tmbuf.tm_year = year - 1900;
376
0
    tmbuf.tm_isdst = -1;
377
0
    stamp = mktime( &tmbuf );
378
0
    if( stamp == (time_t)-1 )
379
0
      {
380
        /* mktime did not work.  Construct an ISO timestring for noon
381
         * of the given day instead.  We keep the use of mktime for 64
382
         * bit system to limit the risk of regressions. */
383
0
        gnupg_isotime_t isobuf;
384
0
        uint64_t tmp64;
385
386
0
        snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
387
0
        tmp64 = isotime2epoch_u64 (isobuf);
388
0
        if (tmp64 == (uint64_t)(-1))
389
0
          return 0;  /* Error.  */
390
0
        if (tmp64 >= (u32)(-1))
391
0
          return 0;   /* Error.  */
392
0
        return (u32)tmp64;
393
0
      }
394
0
    return stamp;
395
0
}
396
397
398
int
399
isotime_p (const char *string)
400
0
{
401
0
  const char *s;
402
0
  int i;
403
404
0
  if (!*string)
405
0
    return 0;
406
0
  for (s=string, i=0; i < 8; i++, s++)
407
0
    if (!digitp (s))
408
0
      return 0;
409
0
  if (*s != 'T')
410
0
      return 0;
411
0
  for (s++, i=9; i < 15; i++, s++)
412
0
    if (!digitp (s))
413
0
      return 0;
414
0
  if (*s == 'Z')
415
0
    s++;
416
0
  if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
417
0
    return 0;  /* Wrong delimiter.  */
418
419
0
  return 1;
420
0
}
421
422
423
/* Scan a string and return true if the string represents the human
424
   readable format of an ISO time.  This format is:
425
      yyyy-mm-dd[ hh[:mm[:ss]]]
426
   Scanning stops at the second space or at a comma.  If DATE_ONLY is
427
   true the time part is not expected and the scanning stops at the
428
   first space or at a comma. */
429
int
430
isotime_human_p (const char *string, int date_only)
431
0
{
432
0
  const char *s;
433
0
  int i;
434
435
0
  if (!*string)
436
0
    return 0;
437
0
  for (s=string, i=0; i < 4; i++, s++)
438
0
    if (!digitp (s))
439
0
      return 0;
440
0
  if (*s != '-')
441
0
    return 0;
442
0
  s++;
443
0
  if (!digitp (s) || !digitp (s+1) || s[2] != '-')
444
0
    return 0;
445
0
  i = atoi_2 (s);
446
0
  if (i < 1 || i > 12)
447
0
    return 0;
448
0
  s += 3;
449
0
  if (!digitp (s) || !digitp (s+1))
450
0
    return 0;
451
0
  i = atoi_2 (s);
452
0
  if (i < 1 || i > 31)
453
0
    return 0;
454
0
  s += 2;
455
0
  if (!*s || *s == ',')
456
0
    return 1; /* Okay; only date given.  */
457
0
  if (!spacep (s))
458
0
    return 0;
459
0
  if (date_only)
460
0
    return 1; /* Okay; only date was requested.  */
461
0
  s++;
462
0
  if (spacep (s))
463
0
    return 1; /* Okay, second space stops scanning.  */
464
0
  if (!digitp (s) || !digitp (s+1))
465
0
    return 0;
466
0
  i = atoi_2 (s);
467
0
  if (i < 0 || i > 23)
468
0
    return 0;
469
0
  s += 2;
470
0
  if (!*s || *s == ',')
471
0
    return 1; /* Okay; only date and hour given.  */
472
0
  if (*s != ':')
473
0
    return 0;
474
0
  s++;
475
0
  if (!digitp (s) || !digitp (s+1))
476
0
    return 0;
477
0
  i = atoi_2 (s);
478
0
  if (i < 0 || i > 59)
479
0
    return 0;
480
0
  s += 2;
481
0
  if (!*s || *s == ',')
482
0
    return 1; /* Okay; only date, hour and minute given.  */
483
0
  if (*s != ':')
484
0
    return 0;
485
0
  s++;
486
0
  if (!digitp (s) || !digitp (s+1))
487
0
    return 0;
488
0
  i = atoi_2 (s);
489
0
  if (i < 0 || i > 60)
490
0
    return 0;
491
0
  s += 2;
492
0
  if (!*s || *s == ',' || spacep (s))
493
0
    return 1; /* Okay; date, hour and minute and second given.  */
494
495
0
  return 0; /* Unexpected delimiter.  */
496
0
}
497
498
/* Convert a standard isotime or a human readable variant into an
499
   isotime structure.  The allowed formats are those described by
500
   isotime_p and isotime_human_p.  The function returns 0 on failure
501
   or the length of the scanned string on success.  */
502
size_t
503
string2isotime (gnupg_isotime_t atime, const char *string)
504
0
{
505
0
  gnupg_isotime_t dummyatime;
506
507
0
  if (!atime)
508
0
    atime = dummyatime;
509
510
0
  atime[0] = 0;
511
0
  if (isotime_p (string))
512
0
    {
513
0
      memcpy (atime, string, 15);
514
0
      atime[15] = 0;
515
0
      return 15;
516
0
    }
517
0
  if (!isotime_human_p (string, 0))
518
0
    return 0;
519
0
  atime[0] = string[0];
520
0
  atime[1] = string[1];
521
0
  atime[2] = string[2];
522
0
  atime[3] = string[3];
523
0
  atime[4] = string[5];
524
0
  atime[5] = string[6];
525
0
  atime[6] = string[8];
526
0
  atime[7] = string[9];
527
0
  atime[8] = 'T';
528
0
  memset (atime+9, '0', 6);
529
0
  atime[15] = 0;
530
0
  if (!spacep (string+10))
531
0
    return 10;
532
0
  if (spacep (string+11))
533
0
    return 11; /* As per def, second space stops scanning.  */
534
0
  atime[9] = string[11];
535
0
  atime[10] = string[12];
536
0
  if (string[13] != ':')
537
0
    return 13;
538
0
  atime[11] = string[14];
539
0
  atime[12] = string[15];
540
0
  if (string[16] != ':')
541
0
    return 16;
542
0
  atime[13] = string[17];
543
0
  atime[14] = string[18];
544
0
  return 19;
545
0
}
546
547
548
/* Helper for isotime2epoch.  Returns 0 on success. */
549
static int
550
isotime_make_tm (const char *string, struct tm *tmbuf)
551
0
{
552
0
  int year, month, day, hour, minu, sec;
553
554
0
  if (!isotime_p (string))
555
0
    return -1;
556
557
0
  year  = atoi_4 (string);
558
0
  month = atoi_2 (string + 4);
559
0
  day   = atoi_2 (string + 6);
560
0
  hour  = atoi_2 (string + 9);
561
0
  minu  = atoi_2 (string + 11);
562
0
  sec   = atoi_2 (string + 13);
563
564
  /* Basic checks.  */
565
0
  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
566
0
      || hour > 23 || minu > 59 || sec > 61 )
567
0
    return -1;
568
569
0
  memset (tmbuf, 0, sizeof *tmbuf);
570
0
  tmbuf->tm_sec  = sec;
571
0
  tmbuf->tm_min  = minu;
572
0
  tmbuf->tm_hour = hour;
573
0
  tmbuf->tm_mday = day;
574
0
  tmbuf->tm_mon  = month-1;
575
0
  tmbuf->tm_year = year - 1900;
576
0
  tmbuf->tm_isdst = -1;
577
0
  return 0;
578
0
}
579
580
581
/* Scan an ISO timestamp and return an Epoch based timestamp.  The
582
   only supported format is "yyyymmddThhmmss[Z]" delimited by white
583
   space, nul, a colon or a comma.  Returns (time_t)(-1) for an
584
   invalid string.  */
585
time_t
586
isotime2epoch (const char *string)
587
0
{
588
0
  struct tm tmbuf;
589
590
0
  if (isotime_make_tm (string, &tmbuf))
591
0
    return (time_t)(-1);
592
593
0
  return timegm (&tmbuf);
594
0
}
595
596
597
uint64_t
598
isotime2epoch_u64 (const char *string)
599
0
{
600
0
  struct tm tmbuf;
601
602
0
  if (isotime_make_tm (string, &tmbuf))
603
0
    return (uint64_t)(-1);
604
605
0
  return timegm_u64 (&tmbuf);
606
0
}
607
608
609
/* Convert an Epoch time to an iso time stamp. */
610
void
611
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
612
0
{
613
0
  if (atime == (time_t)(-1))
614
0
    *timebuf = 0;
615
0
  else
616
0
    {
617
0
      struct tm *tp;
618
0
#ifdef HAVE_GMTIME_R
619
0
      struct tm tmbuf;
620
621
0
      tp = gmtime_r (&atime, &tmbuf);
622
#else
623
      tp = gmtime (&atime);
624
#endif
625
0
      snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
626
0
                1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
627
0
                tp->tm_hour, tp->tm_min, tp->tm_sec);
628
0
    }
629
0
}
630
631
632
/* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
633
   Returns 0 on success.  */
634
int
635
isodate_human_to_tm (const char *string, struct tm *t)
636
0
{
637
0
  int year, month, day;
638
639
0
  if (!isotime_human_p (string, 1))
640
0
    return -1;
641
642
0
  year  = atoi_4 (string);
643
0
  month = atoi_2 (string + 5);
644
0
  day   = atoi_2 (string + 8);
645
646
  /* Basic checks.  */
647
0
  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
648
0
    return -1;
649
650
0
  memset (t, 0, sizeof *t);
651
0
  t->tm_sec  = 0;
652
0
  t->tm_min  = 0;
653
0
  t->tm_hour = 0;
654
0
  t->tm_mday = day;
655
0
  t->tm_mon  = month-1;
656
0
  t->tm_year = year - 1900;
657
0
  t->tm_isdst = -1;
658
0
  return 0;
659
0
}
660
661
662
/* Parse the string TIMESTAMP into a time_t.  The string may either be
663
   seconds since Epoch or in the ISO 8601 format like
664
   "20390815T143012".  Returns 0 for an empty string or seconds since
665
   Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
666
   point to the next non-parsed character in TIMESTRING.
667
668
   This function is a copy of
669
   gpgme/src/conversion.c:_gpgme_parse_timestamp.  If you change it,
670
   then update the other one too.
671
672
   FIXME: Replace users of this function by one of the more modern
673
          functions or change the return type to u64.
674
*/
675
time_t
676
parse_timestamp (const char *timestamp, char **endp)
677
0
{
678
  /* Need to skip leading spaces, because that is what strtoul does
679
     but not our ISO 8601 checking code. */
680
0
  while (*timestamp && *timestamp== ' ')
681
0
    timestamp++;
682
0
  if (!*timestamp)
683
0
    return 0;
684
685
0
  if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
686
0
    {
687
0
      struct tm buf;
688
0
      int year;
689
690
0
      year = atoi_4 (timestamp);
691
0
      if (year < 1900)
692
0
        return (time_t)(-1);
693
694
0
      if (endp)
695
0
        *endp = (char*)(timestamp + 15);
696
697
      /* Fixme: We would better use a configure test to see whether
698
         mktime can handle dates beyond 2038. */
699
0
      if (sizeof (time_t) <= 4 && year >= 2038)
700
0
        return (time_t)2145914603; /* 2037-12-31 23:23:23 */
701
702
0
      memset (&buf, 0, sizeof buf);
703
0
      buf.tm_year = year - 1900;
704
0
      buf.tm_mon = atoi_2 (timestamp+4) - 1;
705
0
      buf.tm_mday = atoi_2 (timestamp+6);
706
0
      buf.tm_hour = atoi_2 (timestamp+9);
707
0
      buf.tm_min = atoi_2 (timestamp+11);
708
0
      buf.tm_sec = atoi_2 (timestamp+13);
709
710
0
      return timegm (&buf);
711
0
    }
712
0
  else
713
0
    return (time_t)strtoul (timestamp, endp, 10);
714
0
}
715
716
717
718
u32
719
add_days_to_timestamp( u32 stamp, u16 days )
720
0
{
721
0
    return stamp + days*86400L;
722
0
}
723
724
725
/****************
726
 * Return a string with a time value in the form: x Y, n D, n H
727
 */
728
729
const char *
730
strtimevalue( u32 value )
731
0
{
732
0
    static char buffer[30];
733
0
    unsigned int years, days, hours, minutes;
734
735
0
    value /= 60;
736
0
    minutes = value % 60;
737
0
    value /= 60;
738
0
    hours = value % 24;
739
0
    value /= 24;
740
0
    days = value % 365;
741
0
    value /= 365;
742
0
    years = value;
743
744
0
    sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
745
0
    if( years )
746
0
  return buffer;
747
0
    if( days )
748
0
  return strchr( buffer, 'y' ) + 1;
749
0
    return strchr( buffer, 'd' ) + 1;
750
0
}
751
752
753
754
/* Return a malloced string with the time elapsed between NOW and
755
   SINCE.  May return NULL on error. */
756
char *
757
elapsed_time_string (time_t since, time_t now)
758
0
{
759
0
  char *result;
760
0
  double diff;
761
0
  unsigned long value;
762
0
  unsigned int days, hours, minutes, seconds;
763
764
0
  if (!now)
765
0
    now = gnupg_get_time ();
766
767
0
  diff = difftime (now, since);
768
0
  if (diff < 0)
769
0
    return xtrystrdup ("time-warp");
770
771
0
  seconds = (unsigned long)diff % 60;
772
0
  value = (unsigned long)(diff / 60);
773
0
  minutes = value % 60;
774
0
  value /= 60;
775
0
  hours = value % 24;
776
0
  value /= 24;
777
0
  days = value % 365;
778
779
0
  if (days)
780
0
    result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds);
781
0
  else if (hours)
782
0
    result = xtryasprintf ("%uh%um%us", hours, minutes, seconds);
783
0
  else if (minutes)
784
0
    result = xtryasprintf ("%um%us", minutes, seconds);
785
0
  else
786
0
    result = xtryasprintf ("%us", seconds);
787
788
0
  return result;
789
0
}
790
791
792
/*
793
 * Note: this function returns GMT
794
 */
795
const char *
796
strtimestamp (u32 stamp)
797
0
{
798
0
  static char buffer[11+5];
799
0
  struct tm *tp;
800
0
  time_t atime = stamp;
801
802
0
  if (IS_INVALID_TIME_T (atime))
803
0
    {
804
0
      strcpy (buffer, "????" "-??" "-??");
805
0
    }
806
0
  else
807
0
    {
808
0
      tp = gmtime( &atime );
809
0
      snprintf (buffer, sizeof buffer, "%04d-%02d-%02d",
810
0
                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
811
0
    }
812
0
  return buffer;
813
0
}
814
815
816
/*
817
 * Note: this function returns GMT
818
 */
819
const char *
820
isotimestamp (u32 stamp)
821
0
{
822
0
  static char buffer[25+5];
823
0
  struct tm *tp;
824
0
  time_t atime = stamp;
825
826
0
  if (IS_INVALID_TIME_T (atime))
827
0
    {
828
0
      strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
829
0
    }
830
0
  else
831
0
    {
832
0
      tp = gmtime ( &atime );
833
0
      snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
834
0
                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
835
0
                tp->tm_hour, tp->tm_min, tp->tm_sec);
836
0
    }
837
0
  return buffer;
838
0
}
839
840
841
/****************
842
 * Note: this function returns local time
843
 */
844
const char *
845
asctimestamp (u32 stamp)
846
8.90k
{
847
8.90k
  static char buffer[80];
848
8.90k
  struct tm *tp;
849
8.90k
  time_t atime = stamp;
850
851
8.90k
  if (IS_INVALID_TIME_T (atime))
852
0
    {
853
0
      strcpy (buffer, "????" "-??" "-??");
854
0
      return buffer;
855
0
    }
856
857
8.90k
  tp = localtime( &atime );
858
8.90k
#ifdef HAVE_STRFTIME
859
8.90k
# if defined(HAVE_NL_LANGINFO)
860
8.90k
  format_time_nl_langinfo (buffer, DIM (buffer), tp);
861
# else /* !HAVE_NL_LANGINFO */
862
#  if HAVE_W32_SYSTEM
863
  {
864
    static int done;
865
866
    if (!done)
867
      {
868
        /* The locale names as used by Windows are in the form
869
         * "German_Germany.1252" or "German_Austria.1252" with
870
         * alternate names similar to Unix, e.g. "de-DE".  However
871
         * that is the theory.  On current Windows and Mingw the
872
         * alternate names do not work.  We would need a table to map
873
         * them from the short names as provided by gpgrt to the long
874
         * names and append some code page.  For now we use "" and
875
         * take the locale from the user's system settings.  Thus the
876
         * standard Unix envvars don't work for time and may mismatch
877
         * with the string translations.  The new UCRT available since
878
         * 2018 has a lot of additional support but that will for sure
879
         * break other things.  We should move to ISO strings to get
880
         * rid of such problems.  */
881
        setlocale (LC_TIME, ".UTF8");
882
        done = 1;
883
        /* log_debug ("LC_ALL  now '%s'\n", setlocale (LC_ALL, NULL)); */
884
        /* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
885
      }
886
  }
887
#  endif /* W32 */
888
   /* FIXME: we should check whether the locale appends a " %Z" These
889
    * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
890
    * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN.  */
891
  strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
892
# endif /* !HAVE_NL_LANGINFO */
893
8.90k
  buffer[DIM(buffer)-1] = 0;
894
#else /* !HAVE_STRFTIME */
895
  mem2str( buffer, asctime(tp), DIM(buffer) );
896
#endif
897
8.90k
  return buffer;
898
8.90k
}
899
900
901
/* Return the timestamp STAMP in RFC-2822 format.  This is always done
902
 * in the C locale.  We return the gmtime to avoid computing the
903
 * timezone. The caller must release the returned string.
904
 *
905
 * Example: "Mon, 27 Jun 2016 1:42:00 +0000".
906
 */
907
char *
908
rfctimestamp (u32 stamp)
909
0
{
910
0
  time_t atime = stamp;
911
0
  struct tm tmbuf, *tp;
912
913
914
0
  if (IS_INVALID_TIME_T (atime))
915
0
    {
916
0
      gpg_err_set_errno (EINVAL);
917
0
      return NULL;
918
0
    }
919
920
0
  tp = gnupg_gmtime (&atime, &tmbuf);
921
0
  if (!tp)
922
0
    return NULL;
923
0
  return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000",
924
0
                       &"SunMonTueWedThuFriSat"[(tp->tm_wday%7)*3],
925
0
                       tp->tm_mday,
926
0
                       &"JanFebMarAprMayJunJulAugSepOctNovDec"
927
0
                       [(tp->tm_mon%12)*3],
928
0
                       tp->tm_year + 1900,
929
0
                       tp->tm_hour,
930
0
                       tp->tm_min,
931
0
                       tp->tm_sec);
932
0
}
933
934
935
static int
936
days_per_year (int y)
937
0
{
938
0
  int s ;
939
940
0
  s = !(y % 4);
941
0
  if ( !(y % 100))
942
0
    if ((y%400))
943
0
      s = 0;
944
0
  return s ? 366 : 365;
945
0
}
946
947
static int
948
days_per_month (int y, int m)
949
0
{
950
0
  int s;
951
952
0
  switch(m)
953
0
    {
954
0
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
955
0
      return 31 ;
956
0
    case 2:
957
0
      s = !(y % 4);
958
0
      if (!(y % 100))
959
0
        if ((y % 400))
960
0
          s = 0;
961
0
      return s? 29 : 28 ;
962
0
    case 4: case 6: case 9: case 11:
963
0
      return 30;
964
0
    }
965
0
  BUG();
966
0
}
967
968
969
/* Convert YEAR, MONTH and DAY into the Julian date.  We assume that
970
   it is already noon.  We do not support dates before 1582-10-15. */
971
static unsigned long
972
date2jd (int year, int month, int day)
973
0
{
974
0
  unsigned long jd;
975
976
0
  jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
977
0
  if (month < 3)
978
0
    year-- ;
979
0
  else
980
0
    jd -= (4 * month + 23) / 10;
981
982
0
  jd += year / 4 - ((year / 100 + 1) *3) / 4;
983
984
0
  return jd ;
985
0
}
986
987
/* Convert a Julian date back to YEAR, MONTH and DAY.  Return day of
988
   the year or 0 on error.  This function uses some more or less
989
   arbitrary limits, most important is that days before 1582 are not
990
   supported. */
991
static int
992
jd2date (unsigned long jd, int *year, int *month, int *day)
993
0
{
994
0
  int y, m, d;
995
0
  long delta;
996
997
0
  if (!jd)
998
0
    return 0 ;
999
0
  if (jd < 1721425 || jd > 2843085)
1000
0
    return 0;
1001
1002
0
  y = (jd - JD_DIFF) / 366;
1003
0
  d = m = 1;
1004
1005
0
  while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
1006
0
    y++;
1007
1008
0
  m = (delta / 31) + 1;
1009
0
  while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
1010
0
    if (++m > 12)
1011
0
      {
1012
0
        m = 1;
1013
0
        y++;
1014
0
      }
1015
1016
0
  d = delta + 1 ;
1017
0
  if (d > days_per_month (y, m))
1018
0
    {
1019
0
      d = 1;
1020
0
      m++;
1021
0
    }
1022
0
  if (m > 12)
1023
0
    {
1024
0
      m = 1;
1025
0
      y++;
1026
0
    }
1027
1028
0
  if (year)
1029
0
    *year = y;
1030
0
  if (month)
1031
0
    *month = m;
1032
0
  if (day)
1033
0
    *day = d ;
1034
1035
0
  return (jd - date2jd (y, 1, 1)) + 1;
1036
0
}
1037
1038
1039
/* Check that the 15 bytes in ATIME represent a valid ISO time.  Note
1040
   that this function does not expect a string but a plain 15 byte
1041
   isotime buffer. */
1042
gpg_error_t
1043
check_isotime (const gnupg_isotime_t atime)
1044
0
{
1045
0
  int i;
1046
0
  const char *s;
1047
1048
0
  if (!*atime)
1049
0
    return gpg_error (GPG_ERR_NO_VALUE);
1050
1051
0
  for (s=atime, i=0; i < 8; i++, s++)
1052
0
    if (!digitp (s))
1053
0
      return gpg_error (GPG_ERR_INV_TIME);
1054
0
  if (*s != 'T')
1055
0
      return gpg_error (GPG_ERR_INV_TIME);
1056
0
  for (s++, i=9; i < 15; i++, s++)
1057
0
    if (!digitp (s))
1058
0
      return gpg_error (GPG_ERR_INV_TIME);
1059
0
  return 0;
1060
0
}
1061
1062
1063
/* Dump the ISO time T to the log stream without a LF.  */
1064
void
1065
dump_isotime (const gnupg_isotime_t t)
1066
0
{
1067
0
  if (!t || !*t)
1068
0
    log_printf ("%s", _("[none]"));
1069
0
  else
1070
0
    log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
1071
0
                t, t+4, t+6, t+9, t+11, t+13);
1072
0
}
1073
1074
1075
/* Copy one ISO date to another, this is inline so that we can do a
1076
   minimal sanity check.  A null date (empty string) is allowed.  */
1077
void
1078
gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
1079
0
{
1080
0
  if (*s)
1081
0
    {
1082
0
      if ((strlen (s) != 15 || s[8] != 'T'))
1083
0
        BUG();
1084
0
      memcpy (d, s, 15);
1085
0
      d[15] = 0;
1086
0
    }
1087
0
  else
1088
0
    *d = 0;
1089
0
}
1090
1091
1092
/* Add SECONDS to ATIME.  SECONDS may not be negative and is limited
1093
   to about the equivalent of 62 years which should be more then
1094
   enough for our purposes. */
1095
gpg_error_t
1096
add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
1097
0
{
1098
0
  gpg_error_t err;
1099
0
  int year, month, day, hour, minute, sec, ndays;
1100
0
  unsigned long jd;
1101
1102
0
  err = check_isotime (atime);
1103
0
  if (err)
1104
0
    return err;
1105
1106
0
  if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
1107
0
    return gpg_error (GPG_ERR_INV_VALUE);
1108
1109
0
  year  = atoi_4 (atime+0);
1110
0
  month = atoi_2 (atime+4);
1111
0
  day   = atoi_2 (atime+6);
1112
0
  hour  = atoi_2 (atime+9);
1113
0
  minute= atoi_2 (atime+11);
1114
0
  sec   = atoi_2 (atime+13);
1115
1116
0
  if (year <= 1582) /* The julian date functions don't support this. */
1117
0
    return gpg_error (GPG_ERR_INV_VALUE);
1118
1119
0
  sec    += nseconds;
1120
0
  minute += sec/60;
1121
0
  sec    %= 60;
1122
0
  hour   += minute/60;
1123
0
  minute %= 60;
1124
0
  ndays  = hour/24;
1125
0
  hour   %= 24;
1126
1127
0
  jd = date2jd (year, month, day) + ndays;
1128
0
  jd2date (jd, &year, &month, &day);
1129
1130
0
  if (year > 9999 || month > 12 || day > 31
1131
0
      || year < 0 || month < 1 || day < 1)
1132
0
    return gpg_error (GPG_ERR_INV_VALUE);
1133
1134
0
  snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
1135
0
            year, month, day, hour, minute, sec);
1136
0
  return 0;
1137
0
}
1138
1139
1140
gpg_error_t
1141
add_days_to_isotime (gnupg_isotime_t atime, int ndays)
1142
0
{
1143
0
  gpg_error_t err;
1144
0
  int year, month, day, hour, minute, sec;
1145
0
  unsigned long jd;
1146
1147
0
  err = check_isotime (atime);
1148
0
  if (err)
1149
0
    return err;
1150
1151
0
  if (ndays < 0 || ndays >= 9999*366 )
1152
0
    return gpg_error (GPG_ERR_INV_VALUE);
1153
1154
0
  year  = atoi_4 (atime+0);
1155
0
  month = atoi_2 (atime+4);
1156
0
  day   = atoi_2 (atime+6);
1157
0
  hour  = atoi_2 (atime+9);
1158
0
  minute= atoi_2 (atime+11);
1159
0
  sec   = atoi_2 (atime+13);
1160
1161
0
  if (year <= 1582) /* The julian date functions don't support this. */
1162
0
    return gpg_error (GPG_ERR_INV_VALUE);
1163
1164
0
  jd = date2jd (year, month, day) + ndays;
1165
0
  jd2date (jd, &year, &month, &day);
1166
1167
0
  if (year > 9999 || month > 12 || day > 31
1168
0
      || year < 0 || month < 1 || day < 1)
1169
0
    return gpg_error (GPG_ERR_INV_VALUE);
1170
1171
0
  snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
1172
0
            year, month, day, hour, minute, sec);
1173
0
  return 0;
1174
0
}