xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/krb5/os/c_ustime.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * lib/crypto/os/c_ustime.c
9  *
10  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  *
33  * krb5_mstimeofday for BSD 4.3
34  */
35 
36 #include "k5-int.h"
37 #include "k5-thread.h"
38 
39 k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
40 
41 struct time_now { krb5_int32 sec, usec; };
42 
43 #if defined(_WIN32)
44 
45    /* Microsoft Windows NT and 95   (32bit)  */
46    /* This one works for WOW (Windows on Windows, ntvdm on Win-NT) */
47 
48 #include <time.h>
49 #include <sys/timeb.h>
50 #include <string.h>
51 
52 static krb5_error_code
53 get_time_now(struct time_now *n)
54 {
55     struct _timeb timeptr;
56     _ftime(&timeptr);
57     n->sec = timeptr.time;
58     n->usec = timeptr.millitm * 1000;
59     return 0;
60 }
61 
62 #else
63 
64 /* Everybody else is UNIX, right?  POSIX 1996 doesn't give us
65    gettimeofday, but what real OS doesn't?  */
66 
67 static krb5_error_code
68 get_time_now(struct time_now *n)
69 {
70     struct timeval tv;
71 #ifdef _KERNEL
72     timestruc_t now;
73 
74     gethrestime(&now);
75     tv.tv_sec = now.tv_sec;
76     tv.tv_usec = now.tv_nsec / (NANOSEC / MICROSEC);
77 #else
78     if (gettimeofday(&tv, (struct timezone *)0) == -1)
79 	return errno;
80 #endif
81 
82     n->sec = tv.tv_sec;
83     n->usec = tv.tv_usec;
84     return 0;
85 }
86 
87 #endif
88 
89 static struct time_now last_time;
90 
91 krb5_error_code
92 krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds)
93 {
94     struct time_now now;
95     krb5_error_code err;
96 
97     err = get_time_now(&now);
98     if (err)
99 	return err;
100 
101     err = k5_mutex_lock(&krb5int_us_time_mutex);
102     if (err)
103 	return err;
104     /* Just guessing: If the number of seconds hasn't changed, yet the
105        microseconds are moving backwards, we probably just got a third
106        instance of returning the same clock value from the system, so
107        the saved value was artificially incremented.
108 
109        On Windows, where we get millisecond accuracy currently, that's
110        quite likely.  On UNIX, it appears that we always get new
111        microsecond values, so this case should never trigger.  */
112     if ((now.sec == last_time.sec) && (now.usec <= last_time.usec)) {
113 	/* Same as last time??? */
114 	now.usec = ++last_time.usec;
115 	if (now.usec >= 1000000) {
116 	    ++now.sec;
117 	    now.usec = 0;
118 	}
119 	/* For now, we're not worrying about the case of enough
120 	   returns of the same value that we roll over now.sec, and
121 	   the next call still gets the previous now.sec value.  */
122     }
123     last_time.sec = now.sec;	/* Remember for next time */
124     last_time.usec = now.usec;
125     (void) k5_mutex_unlock(&krb5int_us_time_mutex);
126 
127     *seconds = now.sec;
128     *microseconds = now.usec;
129     return 0;
130 }
131