diff options
author | Werner Koch <wk@gnupg.org> | 2007-08-28 19:48:13 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2007-08-28 19:48:13 +0200 |
commit | f268889b8ffcd341353210ee141d4c6ded17ef86 (patch) | |
tree | 1757a6ce830b6dd9e2a9d914987e715e7289a920 /common/gettime.c | |
parent | Implemented more gpg-agen options to support certain passphrase policies. (diff) | |
download | gnupg2-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.c | 205 |
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; +} |