xref: /freebsd/crypto/krb5/src/ccapi/lib/ccapi_context_change_time.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* ccapi/lib/ccapi_context_change_time.c */
2 /*
3  * Copyright 2006, 2007 Massachusetts Institute of Technology.
4  * All Rights Reserved.
5  *
6  * Export of this software from the United States of America may
7  * require a specific license from the United States Government.
8  * It is the responsibility of any person or organization contemplating
9  * export to obtain such a license before exporting.
10  *
11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12  * distribute this software and its documentation for any purpose and
13  * without fee is hereby granted, provided that the above copyright
14  * notice appear in all copies and that both that copyright notice and
15  * this permission notice appear in supporting documentation, and that
16  * the name of M.I.T. not be used in advertising or publicity pertaining
17  * to distribution of the software without specific, written prior
18  * permission.  Furthermore if you modify this software you must label
19  * your software as modified software and not distribute it in such a
20  * fashion that it might be confused with the original M.I.T. software.
21  * M.I.T. makes no representations about the suitability of
22  * this software for any purpose.  It is provided "as is" without express
23  * or implied warranty.
24  */
25 
26 #include "ccapi_context_change_time.h"
27 #include "cci_common.h"
28 
29 #include "k5-thread.h"
30 
31 static cci_identifier_t g_change_time_identifer = NULL;
32 static cc_time_t g_change_time = 0;
33 static cc_time_t g_change_time_offset = 0;
34 static k5_mutex_t g_change_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
35 
36 /* ------------------------------------------------------------------------ */
37 
cci_context_change_time_thread_init(void)38 cc_int32 cci_context_change_time_thread_init (void)
39 {
40     return k5_mutex_finish_init(&g_change_time_mutex);
41 }
42 
43 /* ------------------------------------------------------------------------ */
44 
cci_context_change_time_thread_fini(void)45 void cci_context_change_time_thread_fini (void)
46 {
47     k5_mutex_destroy(&g_change_time_mutex);
48 }
49 
50 /* ------------------------------------------------------------------------ */
51 /* WARNING!  Mutex must be locked when calling this!                        */
52 
cci_context_change_time_update_identifier(cci_identifier_t in_new_identifier,cc_uint32 * out_server_ids_match,cc_uint32 * out_old_server_running,cc_uint32 * out_new_server_running)53 static cc_int32 cci_context_change_time_update_identifier (cci_identifier_t  in_new_identifier,
54                                                            cc_uint32        *out_server_ids_match,
55                                                            cc_uint32        *out_old_server_running,
56                                                            cc_uint32        *out_new_server_running)
57 {
58     cc_int32 err = ccNoError;
59     cc_uint32 server_ids_match = 0;
60     cc_uint32 old_server_running = 0;
61     cc_uint32 new_server_running = 0;
62 
63     if (!in_new_identifier) { err = cci_check_error (err); }
64 
65     if (!err && !g_change_time_identifer) {
66        g_change_time_identifer = cci_identifier_uninitialized;
67     }
68 
69     if (!err) {
70         err = cci_identifier_compare_server_id (g_change_time_identifer,
71                                                 in_new_identifier,
72                                                 &server_ids_match);
73     }
74 
75     if (!err && out_old_server_running) {
76         err = cci_identifier_is_initialized (g_change_time_identifer, &old_server_running);
77     }
78 
79     if (!err && out_new_server_running) {
80         err = cci_identifier_is_initialized (in_new_identifier, &new_server_running);
81     }
82 
83     if (!err && !server_ids_match) {
84         cci_identifier_t new_change_time_identifer = NULL;
85 
86         err = cci_identifier_copy (&new_change_time_identifer, in_new_identifier);
87 
88         if (!err) {
89             /* Save the new identifier */
90             if (g_change_time_identifer) {
91                 cci_identifier_release (g_change_time_identifer);
92             }
93             g_change_time_identifer = new_change_time_identifer;
94         }
95     }
96 
97     if (!err) {
98         if (out_server_ids_match  ) { *out_server_ids_match = server_ids_match; }
99         if (out_old_server_running) { *out_old_server_running = old_server_running; }
100         if (out_new_server_running) { *out_new_server_running = new_server_running; }
101     }
102 
103 
104     return cci_check_error (err);
105 }
106 
107 #ifdef TARGET_OS_MAC
108 #pragma mark -
109 #endif
110 
111 /* ------------------------------------------------------------------------ */
112 
cci_context_change_time_get(cc_time_t * out_change_time)113 cc_int32 cci_context_change_time_get (cc_time_t *out_change_time)
114 {
115     cc_int32 err = ccNoError;
116 
117     k5_mutex_lock (&g_change_time_mutex);
118 
119     *out_change_time = g_change_time + g_change_time_offset;
120     k5_mutex_unlock (&g_change_time_mutex);
121 
122     return err;
123 }
124 
125 /* ------------------------------------------------------------------------ */
126 
cci_context_change_time_update(cci_identifier_t in_identifier,cc_time_t in_new_change_time)127 cc_int32 cci_context_change_time_update (cci_identifier_t in_identifier,
128                                          cc_time_t        in_new_change_time)
129 {
130     cc_int32 err = ccNoError;
131     k5_mutex_lock (&g_change_time_mutex);
132 
133     if (!in_identifier) { err = cci_check_error (err); }
134 
135     if (!err) {
136         if (g_change_time < in_new_change_time) {
137             /* Only update if it increases the time.  May be a different server. */
138             g_change_time = in_new_change_time;
139             cci_debug_printf ("%s: setting change time to %d",
140                               __FUNCTION__, in_new_change_time);
141         }
142     }
143 
144     if (!err) {
145         err = cci_context_change_time_update_identifier (in_identifier,
146                                                          NULL, NULL, NULL);
147     }
148 
149     k5_mutex_unlock (&g_change_time_mutex);
150 
151     return err;
152 }
153 
154 /* ------------------------------------------------------------------------ */
155 
cci_context_change_time_sync(cci_identifier_t in_new_identifier)156 cc_int32 cci_context_change_time_sync (cci_identifier_t in_new_identifier)
157 {
158     cc_int32 err = ccNoError;
159     cc_uint32 server_ids_match = 0;
160     cc_uint32 server_was_running = 0;
161     cc_uint32 server_is_running = 0;
162 
163     k5_mutex_lock (&g_change_time_mutex);
164 
165     if (!in_new_identifier) { err = cci_check_error (err); }
166 
167     if (!err) {
168         err = cci_context_change_time_update_identifier (in_new_identifier,
169                                                          &server_ids_match,
170                                                          &server_was_running,
171                                                          &server_is_running);
172     }
173 
174     if (!err && !server_ids_match) {
175         /* Increment the change time so callers re-read */
176         g_change_time_offset++;
177 
178         /* If the server died, absorb the offset */
179         if (server_was_running && !server_is_running) {
180             cc_time_t now = time (NULL);
181 
182             g_change_time += g_change_time_offset;
183             g_change_time_offset = 0;
184 
185             /* Make sure the change time increases, ideally with the current time */
186             g_change_time = (g_change_time < now) ? now : g_change_time;
187         }
188 
189         cci_debug_printf ("%s noticed server changed ("
190                           "server_was_running = %d; server_is_running = %d; "
191                           "g_change_time = %d; g_change_time_offset = %d",
192                           __FUNCTION__, server_was_running, server_is_running,
193                           g_change_time, g_change_time_offset);
194     }
195 
196     k5_mutex_unlock (&g_change_time_mutex);
197 
198     return err;
199 }
200