A local copy of OpenSSL from GitHub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
9.9 KiB

  1. /*
  2. * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the OpenSSL license (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <openssl/e_os2.h>
  10. #include <string.h>
  11. #include <openssl/crypto.h>
  12. #ifdef OPENSSL_SYS_VMS
  13. # if __CRTL_VER >= 70000000 && \
  14. (defined _POSIX_C_SOURCE || !defined _ANSI_C_SOURCE)
  15. # define VMS_GMTIME_OK
  16. # endif
  17. # ifndef VMS_GMTIME_OK
  18. # include <libdtdef.h>
  19. # include <lib$routines.h>
  20. # include <lnmdef.h>
  21. # include <starlet.h>
  22. # include <descrip.h>
  23. # include <stdlib.h>
  24. # endif /* ndef VMS_GMTIME_OK */
  25. #endif
  26. struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result)
  27. {
  28. struct tm *ts = NULL;
  29. #if defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && (!defined(OPENSSL_SYS_VMS) || defined(gmtime_r)) && !defined(OPENSSL_SYS_MACOSX)
  30. /*
  31. * should return &data, but doesn't on some systems, so we don't even
  32. * look at the return value
  33. */
  34. gmtime_r(timer, result);
  35. ts = result;
  36. #elif !defined(OPENSSL_SYS_VMS) || defined(VMS_GMTIME_OK)
  37. ts = gmtime(timer);
  38. if (ts == NULL)
  39. return NULL;
  40. memcpy(result, ts, sizeof(struct tm));
  41. ts = result;
  42. #endif
  43. #if defined( OPENSSL_SYS_VMS) && !defined( VMS_GMTIME_OK)
  44. if (ts == NULL) {
  45. static $DESCRIPTOR(tabnam, "LNM$DCL_LOGICAL");
  46. static $DESCRIPTOR(lognam, "SYS$TIMEZONE_DIFFERENTIAL");
  47. char logvalue[256];
  48. unsigned int reslen = 0;
  49. struct {
  50. short buflen;
  51. short code;
  52. void *bufaddr;
  53. unsigned int *reslen;
  54. } itemlist[] = {
  55. {
  56. 0, LNM$_STRING, 0, 0
  57. },
  58. {
  59. 0, 0, 0, 0
  60. },
  61. };
  62. int status;
  63. time_t t;
  64. /* Get the value for SYS$TIMEZONE_DIFFERENTIAL */
  65. itemlist[0].buflen = sizeof(logvalue);
  66. itemlist[0].bufaddr = logvalue;
  67. itemlist[0].reslen = &reslen;
  68. status = sys$trnlnm(0, &tabnam, &lognam, 0, itemlist);
  69. if (!(status & 1))
  70. return NULL;
  71. logvalue[reslen] = '\0';
  72. t = *timer;
  73. /* The following is extracted from the DEC C header time.h */
  74. /*
  75. ** Beginning in OpenVMS Version 7.0 mktime, time, ctime, strftime
  76. ** have two implementations. One implementation is provided
  77. ** for compatibility and deals with time in terms of local time,
  78. ** the other __utc_* deals with time in terms of UTC.
  79. */
  80. /*
  81. * We use the same conditions as in said time.h to check if we should
  82. * assume that t contains local time (and should therefore be
  83. * adjusted) or UTC (and should therefore be left untouched).
  84. */
  85. # if __CRTL_VER < 70000000 || defined _VMS_V6_SOURCE
  86. /* Get the numerical value of the equivalence string */
  87. status = atoi(logvalue);
  88. /* and use it to move time to GMT */
  89. t -= status;
  90. # endif
  91. /* then convert the result to the time structure */
  92. /*
  93. * Since there was no gmtime_r() to do this stuff for us, we have to
  94. * do it the hard way.
  95. */
  96. {
  97. /*-
  98. * The VMS epoch is the astronomical Smithsonian date,
  99. if I remember correctly, which is November 17, 1858.
  100. Furthermore, time is measure in tenths of microseconds
  101. and stored in quadwords (64 bit integers). unix_epoch
  102. below is January 1st 1970 expressed as a VMS time. The
  103. following code was used to get this number:
  104. #include <stdio.h>
  105. #include <stdlib.h>
  106. #include <lib$routines.h>
  107. #include <starlet.h>
  108. main()
  109. {
  110. unsigned long systime[2];
  111. unsigned short epoch_values[7] =
  112. { 1970, 1, 1, 0, 0, 0, 0 };
  113. lib$cvt_vectim(epoch_values, systime);
  114. printf("%u %u", systime[0], systime[1]);
  115. }
  116. */
  117. unsigned long unix_epoch[2] = { 1273708544, 8164711 };
  118. unsigned long deltatime[2];
  119. unsigned long systime[2];
  120. struct vms_vectime {
  121. short year, month, day, hour, minute, second, centi_second;
  122. } time_values;
  123. long operation;
  124. /*
  125. * Turn the number of seconds since January 1st 1970 to an
  126. * internal delta time. Note that lib$cvt_to_internal_time() will
  127. * assume that t is signed, and will therefore break on 32-bit
  128. * systems some time in 2038.
  129. */
  130. operation = LIB$K_DELTA_SECONDS;
  131. status = lib$cvt_to_internal_time(&operation, &t, deltatime);
  132. /*
  133. * Add the delta time with the Unix epoch and we have the current
  134. * UTC time in internal format
  135. */
  136. status = lib$add_times(unix_epoch, deltatime, systime);
  137. /* Turn the internal time into a time vector */
  138. status = sys$numtim(&time_values, systime);
  139. /* Fill in the struct tm with the result */
  140. result->tm_sec = time_values.second;
  141. result->tm_min = time_values.minute;
  142. result->tm_hour = time_values.hour;
  143. result->tm_mday = time_values.day;
  144. result->tm_mon = time_values.month - 1;
  145. result->tm_year = time_values.year - 1900;
  146. operation = LIB$K_DAY_OF_WEEK;
  147. status = lib$cvt_from_internal_time(&operation,
  148. &result->tm_wday, systime);
  149. result->tm_wday %= 7;
  150. operation = LIB$K_DAY_OF_YEAR;
  151. status = lib$cvt_from_internal_time(&operation,
  152. &result->tm_yday, systime);
  153. result->tm_yday--;
  154. result->tm_isdst = 0; /* There's no way to know... */
  155. ts = result;
  156. }
  157. }
  158. #endif
  159. return ts;
  160. }
  161. /*
  162. * Take a tm structure and add an offset to it. This avoids any OS issues
  163. * with restricted date types and overflows which cause the year 2038
  164. * problem.
  165. */
  166. #define SECS_PER_DAY (24 * 60 * 60)
  167. static long date_to_julian(int y, int m, int d);
  168. static void julian_to_date(long jd, int *y, int *m, int *d);
  169. static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
  170. long *pday, int *psec);
  171. int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec)
  172. {
  173. int time_sec, time_year, time_month, time_day;
  174. long time_jd;
  175. /* Convert time and offset into Julian day and seconds */
  176. if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec))
  177. return 0;
  178. /* Convert Julian day back to date */
  179. julian_to_date(time_jd, &time_year, &time_month, &time_day);
  180. if (time_year < 1900 || time_year > 9999)
  181. return 0;
  182. /* Update tm structure */
  183. tm->tm_year = time_year - 1900;
  184. tm->tm_mon = time_month - 1;
  185. tm->tm_mday = time_day;
  186. tm->tm_hour = time_sec / 3600;
  187. tm->tm_min = (time_sec / 60) % 60;
  188. tm->tm_sec = time_sec % 60;
  189. return 1;
  190. }
  191. int OPENSSL_gmtime_diff(int *pday, int *psec,
  192. const struct tm *from, const struct tm *to)
  193. {
  194. int from_sec, to_sec, diff_sec;
  195. long from_jd, to_jd, diff_day;
  196. if (!julian_adj(from, 0, 0, &from_jd, &from_sec))
  197. return 0;
  198. if (!julian_adj(to, 0, 0, &to_jd, &to_sec))
  199. return 0;
  200. diff_day = to_jd - from_jd;
  201. diff_sec = to_sec - from_sec;
  202. /* Adjust differences so both positive or both negative */
  203. if (diff_day > 0 && diff_sec < 0) {
  204. diff_day--;
  205. diff_sec += SECS_PER_DAY;
  206. }
  207. if (diff_day < 0 && diff_sec > 0) {
  208. diff_day++;
  209. diff_sec -= SECS_PER_DAY;
  210. }
  211. if (pday)
  212. *pday = (int)diff_day;
  213. if (psec)
  214. *psec = diff_sec;
  215. return 1;
  216. }
  217. /* Convert tm structure and offset into julian day and seconds */
  218. static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
  219. long *pday, int *psec)
  220. {
  221. int offset_hms, offset_day;
  222. long time_jd;
  223. int time_year, time_month, time_day;
  224. /* split offset into days and day seconds */
  225. offset_day = offset_sec / SECS_PER_DAY;
  226. /* Avoid sign issues with % operator */
  227. offset_hms = offset_sec - (offset_day * SECS_PER_DAY);
  228. offset_day += off_day;
  229. /* Add current time seconds to offset */
  230. offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
  231. /* Adjust day seconds if overflow */
  232. if (offset_hms >= SECS_PER_DAY) {
  233. offset_day++;
  234. offset_hms -= SECS_PER_DAY;
  235. } else if (offset_hms < 0) {
  236. offset_day--;
  237. offset_hms += SECS_PER_DAY;
  238. }
  239. /*
  240. * Convert date of time structure into a Julian day number.
  241. */
  242. time_year = tm->tm_year + 1900;
  243. time_month = tm->tm_mon + 1;
  244. time_day = tm->tm_mday;
  245. time_jd = date_to_julian(time_year, time_month, time_day);
  246. /* Work out Julian day of new date */
  247. time_jd += offset_day;
  248. if (time_jd < 0)
  249. return 0;
  250. *pday = time_jd;
  251. *psec = offset_hms;
  252. return 1;
  253. }
  254. /*
  255. * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm
  256. */
  257. static long date_to_julian(int y, int m, int d)
  258. {
  259. return (1461 * (y + 4800 + (m - 14) / 12)) / 4 +
  260. (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 -
  261. (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075;
  262. }
  263. static void julian_to_date(long jd, int *y, int *m, int *d)
  264. {
  265. long L = jd + 68569;
  266. long n = (4 * L) / 146097;
  267. long i, j;
  268. L = L - (146097 * n + 3) / 4;
  269. i = (4000 * (L + 1)) / 1461001;
  270. L = L - (1461 * i) / 4 + 31;
  271. j = (80 * L) / 2447;
  272. *d = L - (2447 * j) / 80;
  273. L = j / 11;
  274. *m = j + 2 - (12 * L);
  275. *y = 100 * (n - 49) + i + L;
  276. }