summaryrefslogtreecommitdiffstats
path: root/common/gettime.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-08-28 19:48:13 +0200
committerWerner Koch <wk@gnupg.org>2007-08-28 19:48:13 +0200
commitf268889b8ffcd341353210ee141d4c6ded17ef86 (patch)
tree1757a6ce830b6dd9e2a9d914987e715e7289a920 /common/gettime.c
parentImplemented more gpg-agen options to support certain passphrase policies. (diff)
downloadgnupg2-f268889b8ffcd341353210ee141d4c6ded17ef86.tar.xz
gnupg2-f268889b8ffcd341353210ee141d4c6ded17ef86.zip
Add more passphrase policy rules.
(--max-passphrase-days).
Diffstat (limited to 'common/gettime.c')
-rw-r--r--common/gettime.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/common/gettime.c b/common/gettime.c
index 1814826c0..6b7411b2a 100644
--- a/common/gettime.c
+++ b/common/gettime.c
@@ -30,6 +30,10 @@
static unsigned long timewarp;
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
+/* Correction used to map to real Julian days. */
+#define JD_DIFF 1721060L
+
+
/* Wrapper for the time(3). We use this here so we can fake the time
for tests */
time_t
@@ -363,14 +367,215 @@ asctimestamp( u32 stamp )
+static int
+days_per_year (int y)
+{
+ int s ;
+
+ s = !(y % 4);
+ if ( !(y % 100))
+ if ((y%400))
+ s = 0;
+ return s ? 366 : 365;
+}
+
+static int
+days_per_month (int y, int m)
+{
+ int s;
+
+ switch(m)
+ {
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ return 31 ;
+ case 2:
+ s = !(y % 4);
+ if (!(y % 100))
+ if ((y % 400))
+ s = 0;
+ return s? 29 : 28 ;
+ case 4: case 6: case 9: case 11:
+ return 30;
+ }
+ BUG();
+}
+
+
+/* Convert YEAR, MONTH and DAY into the Julian date. We assume that
+ it is already noon; we dont; support dates before 1582-10-15. */
+static unsigned long
+date2jd (int year, int month, int day)
+{
+ unsigned long jd;
+
+ jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
+ if (month < 3)
+ year-- ;
+ else
+ jd -= (4 * month + 23) / 10;
+
+ jd += year / 4 - ((year / 100 + 1) *3) / 4;
+
+ return jd ;
+}
+
+/* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
+ the year or 0 on error. This function uses some more or less
+ arbitrary limits, most important is that days before 1582 are not
+ supported. */
+static int
+jd2date (unsigned long jd, int *year, int *month, int *day)
+{
+ int y, m, d;
+ long delta;
+
+ if (!jd)
+ return 0 ;
+ if (jd < 1721425 || jd > 2843085)
+ return 0;
+
+ y = (jd - JD_DIFF) / 366;
+ d = m = 1;
+
+ while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
+ y++;
+
+ m = (delta / 31) + 1;
+ while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
+ if (++m > 12)
+ {
+ m = 1;
+ y++;
+ }
+
+ d = delta + 1 ;
+ if (d > days_per_month (y, m))
+ {
+ d = 1;
+ m++;
+ }
+ if (m > 12)
+ {
+ m = 1;
+ y++;
+ }
+
+ if (year)
+ *year = y;
+ if (month)
+ *month = m;
+ if (day)
+ *day = d ;
+
+ return (jd - date2jd (y, 1, 1)) + 1;
+}
+
+
+/* Check that the 15 bytes in ATIME represent a valid ISO time. Note
+ that this function does not expect a string but a plain 15 byte
+ isotime buffer. */
+gpg_error_t
+check_isotime (const gnupg_isotime_t atime)
+{
+ int i;
+ const char *s;
+
+ if (!*atime)
+ return gpg_error (GPG_ERR_NO_VALUE);
+
+ for (s=atime, i=0; i < 8; i++, s++)
+ if (!digitp (s))
+ return gpg_error (GPG_ERR_INV_TIME);
+ if (*s != 'T')
+ return gpg_error (GPG_ERR_INV_TIME);
+ for (s++, i=9; i < 15; i++, s++)
+ if (!digitp (s))
+ return gpg_error (GPG_ERR_INV_TIME);
+ return 0;
+}
+/* Add SECONDS to ATIME. SECONDS may not be negative and is limited
+ to about the equivalent of 62 years which should be more then
+ enough for our purposes. */
+gpg_error_t
+add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
+{
+ gpg_error_t err;
+ int year, month, day, hour, minute, sec, ndays;
+ unsigned long jd;
+
+ err = check_isotime (atime);
+ if (err)
+ return err;
+
+ if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ year = atoi_4 (atime+0);
+ month = atoi_2 (atime+4);
+ day = atoi_2 (atime+6);
+ hour = atoi_2 (atime+9);
+ minute= atoi_2 (atime+11);
+ sec = atoi_2 (atime+13);
+
+ if (year <= 1582) /* The julian date functions don't support this. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ sec += nseconds;
+ minute += sec/60;
+ sec %= 60;
+ hour += minute/60;
+ minute %= 60;
+ ndays = hour/24;
+ hour %= 24;
+
+ jd = date2jd (year, month, day) + ndays;
+ jd2date (jd, &year, &month, &day);
+
+ if (year > 9999 || month > 12 || day > 31
+ || year < 0 || month < 1 || day < 1)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
+ year, month, day, hour, minute, sec);
+ return 0;
+}
+gpg_error_t
+add_days_to_isotime (gnupg_isotime_t atime, int ndays)
+{
+ gpg_error_t err;
+ int year, month, day, hour, minute, sec;
+ unsigned long jd;
+ err = check_isotime (atime);
+ if (err)
+ return err;
+ if (ndays < 0 || ndays >= 9999*366 )
+ return gpg_error (GPG_ERR_INV_VALUE);
+ year = atoi_4 (atime+0);
+ month = atoi_2 (atime+4);
+ day = atoi_2 (atime+6);
+ hour = atoi_2 (atime+9);
+ minute= atoi_2 (atime+11);
+ sec = atoi_2 (atime+13);
+ if (year <= 1582) /* The julian date functions don't support this. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+ jd = date2jd (year, month, day) + ndays;
+ jd2date (jd, &year, &month, &day);
+ if (year > 9999 || month > 12 || day > 31
+ || year < 0 || month < 1 || day < 1)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
+ year, month, day, hour, minute, sec);
+ return 0;
+}