]>
Commit | Line | Data |
---|---|---|
93a17f79 | 1 | /* crypto/o_time.c */ |
ae5c8664 MC |
2 | /* |
3 | * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project | |
4 | * 2001. | |
b8e35bd6 | 5 | */ |
ae5c8664 MC |
6 | /* |
7 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project | |
8 | * 2008. | |
87d3a0cd | 9 | */ |
b8e35bd6 | 10 | /* ==================================================================== |
f8e91264 | 11 | * Copyright (c) 2001-2018 The OpenSSL Project. All rights reserved. |
b8e35bd6 RL |
12 | * |
13 | * Redistribution and use in source and binary forms, with or without | |
14 | * modification, are permitted provided that the following conditions | |
15 | * are met: | |
16 | * | |
17 | * 1. Redistributions of source code must retain the above copyright | |
ae5c8664 | 18 | * notice, this list of conditions and the following disclaimer. |
b8e35bd6 RL |
19 | * |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in | |
22 | * the documentation and/or other materials provided with the | |
23 | * distribution. | |
24 | * | |
25 | * 3. All advertising materials mentioning features or use of this | |
26 | * software must display the following acknowledgment: | |
27 | * "This product includes software developed by the OpenSSL Project | |
28 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
29 | * | |
30 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
31 | * endorse or promote products derived from this software without | |
32 | * prior written permission. For written permission, please contact | |
33 | * licensing@OpenSSL.org. | |
34 | * | |
35 | * 5. Products derived from this software may not be called "OpenSSL" | |
36 | * nor may "OpenSSL" appear in their names without prior written | |
37 | * permission of the OpenSSL Project. | |
38 | * | |
39 | * 6. Redistributions of any form whatsoever must retain the following | |
40 | * acknowledgment: | |
41 | * "This product includes software developed by the OpenSSL Project | |
42 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
43 | * | |
44 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
45 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
47 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
48 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
49 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
50 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
51 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
53 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
54 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
55 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
56 | * ==================================================================== | |
57 | * | |
58 | * This product includes cryptographic software written by Eric Young | |
59 | * (eay@cryptsoft.com). This product includes software written by Tim | |
60 | * Hudson (tjh@cryptsoft.com). | |
61 | * | |
62 | */ | |
63 | ||
64 | #include <openssl/e_os2.h> | |
5cd6571f | 65 | #include <string.h> |
b8e35bd6 RL |
66 | #include "o_time.h" |
67 | ||
68 | #ifdef OPENSSL_SYS_VMS | |
01d2e27a RL |
69 | # if __CRTL_VER >= 70000000 && \ |
70 | (defined _POSIX_C_SOURCE || !defined _ANSI_C_SOURCE) | |
71 | # define VMS_GMTIME_OK | |
72 | # endif | |
73 | # ifndef VMS_GMTIME_OK | |
74 | # include <libdtdef.h> | |
75 | # include <lib$routines.h> | |
76 | # include <lnmdef.h> | |
77 | # include <starlet.h> | |
78 | # include <descrip.h> | |
79 | # include <stdlib.h> | |
ae5c8664 | 80 | # endif /* ndef VMS_GMTIME_OK */ |
23ffde2e RL |
81 | |
82 | ||
83 | /* | |
84 | * Needed to pick up the correct definitions and declarations in some of the | |
85 | * DEC C Header Files (*.H). | |
86 | */ | |
87 | # define __NEW_STARLET 1 | |
88 | ||
89 | # if (defined(__alpha) || defined(__ia64)) | |
90 | # include <iledef.h> | |
91 | # else | |
92 | ||
93 | /* VAX */ | |
94 | typedef struct _ile3 { /* Copied from ILEDEF.H for Alpha */ | |
95 | # pragma __nomember_alignment | |
96 | unsigned short int ile3$w_length; /* Length of buffer in bytes */ | |
97 | unsigned short int ile3$w_code; /* Item code value */ | |
98 | void *ile3$ps_bufaddr; /* Buffer address */ | |
99 | unsigned short int *ile3$ps_retlen_addr; /* Address of word for returned length */ | |
100 | } ILE3; | |
101 | # endif /* alpha || ia64 */ | |
102 | #endif /* OPENSSL_SYS_VMS */ | |
b8e35bd6 RL |
103 | |
104 | struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result) | |
ae5c8664 MC |
105 | { |
106 | struct tm *ts = NULL; | |
b8e35bd6 | 107 | |
8552d918 | 108 | #if defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_OS2) && (!defined(OPENSSL_SYS_VMS) || defined(gmtime_r)) && !defined(OPENSSL_SYS_SUNOS) |
b70dc3a6 GV |
109 | if (gmtime_r(timer, result) == NULL) |
110 | return NULL; | |
ae5c8664 | 111 | ts = result; |
6a285edd MS |
112 | #elif defined (OPENSSL_SYS_WINDOWS) && defined(_MSC_VER) && _MSC_VER >= 1400 |
113 | if (gmtime_s(result, timer)) | |
114 | return NULL; | |
115 | ts = result; | |
01d2e27a | 116 | #elif !defined(OPENSSL_SYS_VMS) || defined(VMS_GMTIME_OK) |
ae5c8664 MC |
117 | ts = gmtime(timer); |
118 | if (ts == NULL) | |
119 | return NULL; | |
52c4c51f | 120 | |
ae5c8664 MC |
121 | memcpy(result, ts, sizeof(struct tm)); |
122 | ts = result; | |
b8e35bd6 | 123 | #endif |
01d2e27a | 124 | #if defined( OPENSSL_SYS_VMS) && !defined( VMS_GMTIME_OK) |
ae5c8664 MC |
125 | if (ts == NULL) { |
126 | static $DESCRIPTOR(tabnam, "LNM$DCL_LOGICAL"); | |
127 | static $DESCRIPTOR(lognam, "SYS$TIMEZONE_DIFFERENTIAL"); | |
128 | char logvalue[256]; | |
129 | unsigned int reslen = 0; | |
23ffde2e RL |
130 | # if __INITIAL_POINTER_SIZE == 64 |
131 | ILEB_64 itemlist[2], *pitem; | |
132 | # else | |
133 | ILE3 itemlist[2], *pitem; | |
134 | # endif | |
ae5c8664 MC |
135 | int status; |
136 | time_t t; | |
137 | ||
23ffde2e RL |
138 | |
139 | /* | |
140 | * Setup an itemlist for the call to $TRNLNM - Translate Logical Name. | |
141 | */ | |
142 | pitem = itemlist; | |
143 | ||
144 | # if __INITIAL_POINTER_SIZE == 64 | |
145 | pitem->ileb_64$w_mbo = 1; | |
146 | pitem->ileb_64$w_code = LNM$_STRING; | |
147 | pitem->ileb_64$l_mbmo = -1; | |
c6738fd2 | 148 | pitem->ileb_64$q_length = sizeof(logvalue); |
23ffde2e RL |
149 | pitem->ileb_64$pq_bufaddr = logvalue; |
150 | pitem->ileb_64$pq_retlen_addr = (unsigned __int64 *) &reslen; | |
151 | pitem++; | |
152 | /* Last item of the item list is null terminated */ | |
153 | pitem->ileb_64$q_length = pitem->ileb_64$w_code = 0; | |
154 | # else | |
c6738fd2 | 155 | pitem->ile3$w_length = sizeof(logvalue); |
23ffde2e RL |
156 | pitem->ile3$w_code = LNM$_STRING; |
157 | pitem->ile3$ps_bufaddr = logvalue; | |
158 | pitem->ile3$ps_retlen_addr = (unsigned short int *) &reslen; | |
159 | pitem++; | |
160 | /* Last item of the item list is null terminated */ | |
161 | pitem->ile3$w_length = pitem->ile3$w_code = 0; | |
162 | # endif | |
163 | ||
164 | ||
ae5c8664 | 165 | /* Get the value for SYS$TIMEZONE_DIFFERENTIAL */ |
ae5c8664 MC |
166 | status = sys$trnlnm(0, &tabnam, &lognam, 0, itemlist); |
167 | if (!(status & 1)) | |
168 | return NULL; | |
169 | logvalue[reslen] = '\0'; | |
170 | ||
171 | t = *timer; | |
334ef049 | 172 | |
23ffde2e | 173 | /* The following is extracted from the DEC C header time.h */ |
ae5c8664 MC |
174 | /* |
175 | ** Beginning in OpenVMS Version 7.0 mktime, time, ctime, strftime | |
176 | ** have two implementations. One implementation is provided | |
177 | ** for compatibility and deals with time in terms of local time, | |
178 | ** the other __utc_* deals with time in terms of UTC. | |
179 | */ | |
180 | /* | |
181 | * We use the same conditions as in said time.h to check if we should | |
182 | * assume that t contains local time (and should therefore be | |
183 | * adjusted) or UTC (and should therefore be left untouched). | |
184 | */ | |
185 | # if __CRTL_VER < 70000000 || defined _VMS_V6_SOURCE | |
186 | /* Get the numerical value of the equivalence string */ | |
187 | status = atoi(logvalue); | |
188 | ||
189 | /* and use it to move time to GMT */ | |
190 | t -= status; | |
191 | # endif | |
b8e35bd6 | 192 | |
ae5c8664 MC |
193 | /* then convert the result to the time structure */ |
194 | ||
195 | /* | |
196 | * Since there was no gmtime_r() to do this stuff for us, we have to | |
197 | * do it the hard way. | |
198 | */ | |
199 | { | |
83975c80 MC |
200 | /*- |
201 | * The VMS epoch is the astronomical Smithsonian date, | |
202 | if I remember correctly, which is November 17, 1858. | |
203 | Furthermore, time is measure in thenths of microseconds | |
204 | and stored in quadwords (64 bit integers). unix_epoch | |
205 | below is January 1st 1970 expressed as a VMS time. The | |
206 | following code was used to get this number: | |
207 | ||
208 | #include <stdio.h> | |
209 | #include <stdlib.h> | |
210 | #include <lib$routines.h> | |
211 | #include <starlet.h> | |
212 | ||
213 | main() | |
214 | { | |
215 | unsigned long systime[2]; | |
216 | unsigned short epoch_values[7] = | |
217 | { 1970, 1, 1, 0, 0, 0, 0 }; | |
218 | ||
219 | lib$cvt_vectim(epoch_values, systime); | |
220 | ||
221 | printf("%u %u", systime[0], systime[1]); | |
222 | } | |
223 | */ | |
ae5c8664 MC |
224 | unsigned long unix_epoch[2] = { 1273708544, 8164711 }; |
225 | unsigned long deltatime[2]; | |
226 | unsigned long systime[2]; | |
227 | struct vms_vectime { | |
228 | short year, month, day, hour, minute, second, centi_second; | |
229 | } time_values; | |
230 | long operation; | |
231 | ||
232 | /* | |
233 | * Turn the number of seconds since January 1st 1970 to an | |
234 | * internal delta time. Note that lib$cvt_to_internal_time() will | |
235 | * assume that t is signed, and will therefore break on 32-bit | |
236 | * systems some time in 2038. | |
237 | */ | |
238 | operation = LIB$K_DELTA_SECONDS; | |
239 | status = lib$cvt_to_internal_time(&operation, &t, deltatime); | |
240 | ||
241 | /* | |
242 | * Add the delta time with the Unix epoch and we have the current | |
243 | * UTC time in internal format | |
244 | */ | |
245 | status = lib$add_times(unix_epoch, deltatime, systime); | |
246 | ||
247 | /* Turn the internal time into a time vector */ | |
248 | status = sys$numtim(&time_values, systime); | |
249 | ||
250 | /* Fill in the struct tm with the result */ | |
251 | result->tm_sec = time_values.second; | |
252 | result->tm_min = time_values.minute; | |
253 | result->tm_hour = time_values.hour; | |
254 | result->tm_mday = time_values.day; | |
255 | result->tm_mon = time_values.month - 1; | |
256 | result->tm_year = time_values.year - 1900; | |
257 | ||
258 | operation = LIB$K_DAY_OF_WEEK; | |
259 | status = lib$cvt_from_internal_time(&operation, | |
260 | &result->tm_wday, systime); | |
261 | result->tm_wday %= 7; | |
262 | ||
263 | operation = LIB$K_DAY_OF_YEAR; | |
264 | status = lib$cvt_from_internal_time(&operation, | |
265 | &result->tm_yday, systime); | |
266 | result->tm_yday--; | |
267 | ||
268 | result->tm_isdst = 0; /* There's no way to know... */ | |
269 | ||
270 | ts = result; | |
271 | } | |
272 | } | |
b8e35bd6 | 273 | #endif |
ae5c8664 MC |
274 | return ts; |
275 | } | |
87d3a0cd | 276 | |
ae5c8664 MC |
277 | /* |
278 | * Take a tm structure and add an offset to it. This avoids any OS issues | |
87d3a0cd DSH |
279 | * with restricted date types and overflows which cause the year 2038 |
280 | * problem. | |
281 | */ | |
282 | ||
283 | #define SECS_PER_DAY (24 * 60 * 60) | |
284 | ||
285 | static long date_to_julian(int y, int m, int d); | |
286 | static void julian_to_date(long jd, int *y, int *m, int *d); | |
904348a4 | 287 | static int julian_adj(const struct tm *tm, int off_day, long offset_sec, |
ae5c8664 | 288 | long *pday, int *psec); |
87d3a0cd DSH |
289 | |
290 | int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) | |
ae5c8664 MC |
291 | { |
292 | int time_sec, time_year, time_month, time_day; | |
293 | long time_jd; | |
294 | ||
295 | /* Convert time and offset into julian day and seconds */ | |
296 | if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec)) | |
297 | return 0; | |
904348a4 | 298 | |
ae5c8664 | 299 | /* Convert Julian day back to date */ |
904348a4 | 300 | |
ae5c8664 | 301 | julian_to_date(time_jd, &time_year, &time_month, &time_day); |
904348a4 | 302 | |
ae5c8664 MC |
303 | if (time_year < 1900 || time_year > 9999) |
304 | return 0; | |
904348a4 | 305 | |
ae5c8664 | 306 | /* Update tm structure */ |
904348a4 | 307 | |
ae5c8664 MC |
308 | tm->tm_year = time_year - 1900; |
309 | tm->tm_mon = time_month - 1; | |
310 | tm->tm_mday = time_day; | |
904348a4 | 311 | |
ae5c8664 MC |
312 | tm->tm_hour = time_sec / 3600; |
313 | tm->tm_min = (time_sec / 60) % 60; | |
314 | tm->tm_sec = time_sec % 60; | |
904348a4 | 315 | |
ae5c8664 | 316 | return 1; |
904348a4 | 317 | |
904348a4 DSH |
318 | } |
319 | ||
320 | int OPENSSL_gmtime_diff(int *pday, int *psec, | |
ae5c8664 MC |
321 | const struct tm *from, const struct tm *to) |
322 | { | |
323 | int from_sec, to_sec, diff_sec; | |
324 | long from_jd, to_jd, diff_day; | |
325 | if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) | |
326 | return 0; | |
327 | if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) | |
328 | return 0; | |
329 | diff_day = to_jd - from_jd; | |
330 | diff_sec = to_sec - from_sec; | |
331 | /* Adjust differences so both positive or both negative */ | |
332 | if (diff_day > 0 && diff_sec < 0) { | |
333 | diff_day--; | |
334 | diff_sec += SECS_PER_DAY; | |
335 | } | |
336 | if (diff_day < 0 && diff_sec > 0) { | |
337 | diff_day++; | |
338 | diff_sec -= SECS_PER_DAY; | |
339 | } | |
340 | ||
341 | if (pday) | |
342 | *pday = (int)diff_day; | |
343 | if (psec) | |
344 | *psec = diff_sec; | |
345 | ||
346 | return 1; | |
347 | ||
348 | } | |
349 | ||
904348a4 DSH |
350 | /* Convert tm structure and offset into julian day and seconds */ |
351 | static int julian_adj(const struct tm *tm, int off_day, long offset_sec, | |
ae5c8664 MC |
352 | long *pday, int *psec) |
353 | { | |
354 | int offset_hms, offset_day; | |
355 | long time_jd; | |
356 | int time_year, time_month, time_day; | |
357 | /* split offset into days and day seconds */ | |
358 | offset_day = offset_sec / SECS_PER_DAY; | |
359 | /* Avoid sign issues with % operator */ | |
360 | offset_hms = offset_sec - (offset_day * SECS_PER_DAY); | |
361 | offset_day += off_day; | |
362 | /* Add current time seconds to offset */ | |
363 | offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; | |
364 | /* Adjust day seconds if overflow */ | |
365 | if (offset_hms >= SECS_PER_DAY) { | |
366 | offset_day++; | |
367 | offset_hms -= SECS_PER_DAY; | |
368 | } else if (offset_hms < 0) { | |
369 | offset_day--; | |
370 | offset_hms += SECS_PER_DAY; | |
371 | } | |
372 | ||
373 | /* | |
374 | * Convert date of time structure into a Julian day number. | |
375 | */ | |
376 | ||
377 | time_year = tm->tm_year + 1900; | |
378 | time_month = tm->tm_mon + 1; | |
379 | time_day = tm->tm_mday; | |
380 | ||
381 | time_jd = date_to_julian(time_year, time_month, time_day); | |
382 | ||
383 | /* Work out Julian day of new date */ | |
384 | time_jd += offset_day; | |
385 | ||
386 | if (time_jd < 0) | |
387 | return 0; | |
388 | ||
389 | *pday = time_jd; | |
390 | *psec = offset_hms; | |
391 | return 1; | |
392 | } | |
393 | ||
394 | /* | |
395 | * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm | |
87d3a0cd DSH |
396 | */ |
397 | static long date_to_julian(int y, int m, int d) | |
398 | { | |
ae5c8664 MC |
399 | return (1461 * (y + 4800 + (m - 14) / 12)) / 4 + |
400 | (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - | |
401 | (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075; | |
87d3a0cd DSH |
402 | } |
403 | ||
404 | static void julian_to_date(long jd, int *y, int *m, int *d) | |
ae5c8664 MC |
405 | { |
406 | long L = jd + 68569; | |
407 | long n = (4 * L) / 146097; | |
408 | long i, j; | |
409 | ||
410 | L = L - (146097 * n + 3) / 4; | |
411 | i = (4000 * (L + 1)) / 1461001; | |
412 | L = L - (1461 * i) / 4 + 31; | |
413 | j = (80 * L) / 2447; | |
414 | *d = L - (2447 * j) / 80; | |
415 | L = j / 11; | |
416 | *m = j + 2 - (12 * L); | |
417 | *y = 100 * (n - 49) + i + L; | |
418 | } | |
87d3a0cd DSH |
419 | |
420 | #ifdef OPENSSL_TIME_TEST | |
421 | ||
ae5c8664 | 422 | # include <stdio.h> |
87d3a0cd | 423 | |
ae5c8664 MC |
424 | /* |
425 | * Time checking test code. Check times are identical for a wide range of | |
87d3a0cd DSH |
426 | * offsets. This should be run on a machine with 64 bit time_t or it will |
427 | * trigger the very errors the routines fix. | |
428 | */ | |
429 | ||
430 | int main(int argc, char **argv) | |
ae5c8664 MC |
431 | { |
432 | long offset; | |
433 | for (offset = 0; offset < 1000000; offset++) { | |
434 | check_time(offset); | |
435 | check_time(-offset); | |
436 | check_time(offset * 1000); | |
437 | check_time(-offset * 1000); | |
438 | } | |
439 | } | |
87d3a0cd DSH |
440 | |
441 | int check_time(long offset) | |
ae5c8664 MC |
442 | { |
443 | struct tm tm1, tm2, o1; | |
444 | int off_day, off_sec; | |
445 | long toffset; | |
446 | time_t t1, t2; | |
447 | time(&t1); | |
448 | t2 = t1 + offset; | |
449 | OPENSSL_gmtime(&t2, &tm2); | |
450 | OPENSSL_gmtime(&t1, &tm1); | |
451 | o1 = tm1; | |
452 | OPENSSL_gmtime_adj(&tm1, 0, offset); | |
453 | if ((tm1.tm_year != tm2.tm_year) || | |
454 | (tm1.tm_mon != tm2.tm_mon) || | |
455 | (tm1.tm_mday != tm2.tm_mday) || | |
456 | (tm1.tm_hour != tm2.tm_hour) || | |
457 | (tm1.tm_min != tm2.tm_min) || (tm1.tm_sec != tm2.tm_sec)) { | |
458 | fprintf(stderr, "TIME ERROR!!\n"); | |
459 | fprintf(stderr, "Time1: %d/%d/%d, %d:%02d:%02d\n", | |
460 | tm2.tm_mday, tm2.tm_mon + 1, tm2.tm_year + 1900, | |
461 | tm2.tm_hour, tm2.tm_min, tm2.tm_sec); | |
462 | fprintf(stderr, "Time2: %d/%d/%d, %d:%02d:%02d\n", | |
463 | tm1.tm_mday, tm1.tm_mon + 1, tm1.tm_year + 1900, | |
464 | tm1.tm_hour, tm1.tm_min, tm1.tm_sec); | |
465 | return 0; | |
466 | } | |
467 | OPENSSL_gmtime_diff(&o1, &tm1, &off_day, &off_sec); | |
468 | toffset = (long)off_day *SECS_PER_DAY + off_sec; | |
469 | if (offset != toffset) { | |
470 | fprintf(stderr, "TIME OFFSET ERROR!!\n"); | |
471 | fprintf(stderr, "Expected %ld, Got %ld (%d:%d)\n", | |
472 | offset, toffset, off_day, off_sec); | |
473 | return 0; | |
474 | } | |
475 | return 1; | |
476 | } | |
87d3a0cd DSH |
477 | |
478 | #endif |