1 /*
2 * Copyright 1999-2006 University of Chicago
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 #include "globus_i_handler_wsse_cred.h"
19 #include "globus_ws_security.h"
20 #include "openssl/x509.h"
21
22 #define WSSE_CACHED_USER_SUBJECT_HASH "WSSE_CACHED_USER_SUBJECT_HASH"
23
24 static unsigned long int cached_hash = 0;
25 static globus_i_handler_wsse_cache_t pkipath_table = NULL;
26 static globus_mutex_t pkipath_table_mutex;
27
28 globus_result_t
29 globus_i_handler_wsse_cred_pkipath_table_init()
30 718 {
31 globus_reltime_t expiration;
32 718 globus_mutex_init(&pkipath_table_mutex, NULL);
33 718 globus_mutex_lock(&pkipath_table_mutex);
34
35 718 cached_hash = 0;
36 718 pkipath_table = NULL;
37
38 /* expiration = 5 mins */
39 718 GlobusTimeReltimeSet(expiration, (5 * 60), 0);
40 718 globus_i_handler_wsse_cache_init(
41 &pkipath_table,
42 20, /* cache size for creds */
43 expiration);
44 718 globus_mutex_unlock(&pkipath_table_mutex);
45
46 718 return GLOBUS_SUCCESS;
47 }
48
49 void
50 globus_i_handler_wsse_cred_pkipath_table_destroy()
51 150 {
52 150 globus_mutex_lock(&pkipath_table_mutex);
53 150 globus_i_handler_wsse_cache_destroy(pkipath_table);
54 150 globus_mutex_unlock(&pkipath_table_mutex);
55
56 150 globus_mutex_destroy(&pkipath_table_mutex);
57
58 150 cached_hash = 0;
59 150 pkipath_table = NULL;
60 150 }
61
62 unsigned long
63 globus_i_handler_wsse_cred_subject_hash(
64 globus_gsi_cred_handle_t credential)
65 0 {
66 unsigned long hash;
67 X509_NAME * name;
68
69 0 globus_gsi_cred_get_X509_subject_name(credential, &name);
70 0 hash = X509_NAME_hash(name);
71 0 X509_NAME_free(name);
72 0 return hash;
73 }
74
75 void
76 globus_i_handler_wsse_cache_init (
77 globus_i_handler_wsse_cache_t * new_cache,
78 int capacity,
79 globus_reltime_t reltime_limit)
80 718 {
81 globus_i_handler_wsse_cache_t cache;
82
83 718 if ( new_cache == NULL ) return;
84
85
86 718 cache = globus_malloc(sizeof(struct globus_i_handler_wsse_cache_s));
87 718 if(!cache)
88 {
89 0 *new_cache = NULL;
90 0 return;
91 }
92
93 718 globus_hashtable_init (&(cache->handlemap),
94 capacity,
95 globus_hashtable_ulong_hash,
96 globus_hashtable_ulong_keyeq);
97 718 globus_fifo_init (&(cache->handles));
98
99 718 cache->capacity_limit = capacity;
100 718 cache->entry_count = 0;
101 718 GlobusTimeReltimeCopy(cache->time_limit, reltime_limit);
102
103 718 *new_cache = cache;
104 }
105
106 void
107 globus_i_handler_wsse_cache_destroy (
108 globus_i_handler_wsse_cache_t cache)
109 150 {
110 150 if(cache == NULL) return;
111
112 300 while(!globus_fifo_empty(&(cache->handles)))
113 {
114 globus_gsi_cred_handle_t cred;
115 char * pkipath_buff;
116 int pkipath_length;
117 0 globus_i_handler_wsse_cache_remove(
118 cache,
119 (int)globus_fifo_dequeue(&(cache->handles)),
120 &cred, &pkipath_buff, &pkipath_length);
121
122 0 if(cred)
123 {
124 0 globus_gsi_cred_handle_destroy(cred);
125 }
126
127 0 if(pkipath_buff)
128 {
129 0 free(pkipath_buff);
130 }
131 }
132 150 globus_hashtable_destroy_all(
133 &(cache->handlemap),
134 globus_i_handler_wsse_pkipath_entry_destroy);
135 150 globus_fifo_destroy (&(cache->handles));
136
137 150 globus_free(cache);
138 }
139
140 globus_result_t
141 globus_i_handler_wsse_cache_insert(
142 globus_i_handler_wsse_cache_t cache,
143 globus_gsi_cred_handle_t credential,
144 unsigned long * hash)
145 0 {
146 globus_i_handler_wsse_pkipath_entry_t * entry;
147 0 globus_result_t result = GLOBUS_SUCCESS;
148 unsigned long subject_hash;
149
150 0 if(credential == NULL) return GLOBUS_FAILURE;
151
152 0 subject_hash = globus_i_handler_wsse_cred_subject_hash(
153 credential);
154
155 0 *hash = subject_hash;
156
157 0 if (cache == NULL) return GLOBUS_FAILURE;
158
159 0 if ( cache->entry_count > cache->capacity_limit )
160 {
161 globus_gsi_cred_handle_t cred;
162 char * pkipath_buff;
163 0 globus_i_handler_wsse_cache_remove (
164 cache,
165 (int)globus_fifo_dequeue ( &(cache->handles) ),
166 &cred, &pkipath_buff, NULL);
167
168 0 if(cred)
169 {
170 0 globus_gsi_cred_handle_destroy(cred);
171 }
172
173 0 if(pkipath_buff)
174 {
175 0 globus_free(pkipath_buff);
176 }
177 }
178
179 0 entry = globus_malloc(sizeof(globus_i_handler_wsse_pkipath_entry_t));
180 0 if(!entry)
181 {
182 0 result = GlobusWSSEErrorOutOfMemory(
183 sizeof(globus_i_handler_wsse_pkipath_entry_t));
184 0 return result;
185 }
186 0 memset(entry, 0, sizeof(globus_i_handler_wsse_pkipath_entry_t));
187
188 0 entry->subject = subject_hash;
189 0 result = globus_gsi_cred_handle_copy(credential, &entry->credential);
190 0 if(result != GLOBUS_SUCCESS)
191 {
192 0 goto free_entry;
193 }
194
195 0 result = globus_ws_security_create_pkipath(
196 entry->credential, &entry->pkipath_buffer, &entry->pkipath_length);
197 0 if(result != GLOBUS_SUCCESS)
198 {
199 0 goto free_entry;
200 }
201
202 0 GlobusTimeAbstimeGetCurrent(entry->entry_time);
203
204 0 globus_hashtable_insert(
205 &(cache->handlemap),
206 (void *)entry->subject,
207 (void *)entry);
208 0 globus_fifo_enqueue (&(cache->handles), (void *)entry->subject);
209
210 0 cache->entry_count += 1;
211
212 0 goto exit;
213
214 0 free_entry:
215
216 0 globus_i_handler_wsse_pkipath_entry_destroy(entry);
217
218 0 exit:
219
220 0 return result;
221 }
222
223 globus_result_t
224 globus_i_handler_wsse_cache_lookup (
225 globus_i_handler_wsse_cache_t cache,
226 unsigned long subject_hash,
227 globus_gsi_cred_handle_t * credential,
228 char ** pkipath_buffer,
229 int * pkipath_length)
230 0 {
231 globus_i_handler_wsse_pkipath_entry_t * entry;
232 0 globus_result_t result = GLOBUS_SUCCESS;
233
234 0 if ( cache == NULL ) return GLOBUS_FAILURE;
235
236 0 entry = globus_hashtable_lookup (&(cache->handlemap),
237 (void *)subject_hash);
238 0 if(entry)
239 {
240 0 if(!globus_time_reltime_is_infinity(&cache->time_limit))
241 {
242 char * tmp_buff;
243 int tmp_length;
244 globus_gsi_cred_handle_t cred;
245 globus_reltime_t diff;
246 globus_abstime_t current;
247 0 GlobusTimeAbstimeGetCurrent(current);
248 0 GlobusTimeAbstimeDiff(diff, entry->entry_time, current);
249 0 if(globus_reltime_cmp(&diff, &cache->time_limit) >= 0)
250 {
251 /* expired cache entry. must remove */
252 0 globus_i_handler_wsse_cache_remove(cache, subject_hash,
253 &cred,
254 &tmp_buff, &tmp_length);
255 0 if(tmp_buff)
256 {
257 0 globus_free(tmp_buff);
258 }
259
260 0 if(cred)
261 {
262 0 globus_gsi_cred_handle_destroy(cred);
263 }
264
265 0 result = GLOBUS_FAILURE;
266 0 goto exit;
267 }
268 }
269
270 0 if(credential)
271 {
272 0 *credential = entry->credential;
273 }
274
275 0 if(pkipath_buffer)
276 {
277 0 *pkipath_buffer = entry->pkipath_buffer;
278 0 *pkipath_length = entry->pkipath_length;
279 }
280 }
281 else
282 {
283 0 result = GLOBUS_FAILURE;
284 }
285
286 0 exit:
287
288 0 return result;
289 }
290
291 globus_result_t
292 globus_i_handler_wsse_cache_remove (
293 globus_i_handler_wsse_cache_t cache,
294 unsigned long subject_hash,
295 globus_gsi_cred_handle_t * credential,
296 char ** pkipath_buffer,
297 int * pkipath_length)
298 0 {
299 0 globus_result_t result = GLOBUS_SUCCESS;
300 globus_i_handler_wsse_pkipath_entry_t * entry;
301
302 0 if ( cache == NULL ) return GLOBUS_FAILURE;
303
304 0 entry = globus_hashtable_remove (&(cache->handlemap),
305 (void *)subject_hash);
306 0 globus_fifo_remove (&(cache->handles), (void *)subject_hash);
307 0 if ( entry != NULL ) cache->entry_count -= 1;
308
309 0 if(entry)
310 {
311 0 if(pkipath_buffer)
312 {
313 0 *pkipath_buffer = entry->pkipath_buffer;
314 0 *pkipath_length = entry->pkipath_length;
315 }
316 else
317 {
318 0 globus_free(entry->pkipath_buffer);
319 }
320
321 0 if(credential)
322 {
323 0 *credential = entry->credential;
324 }
325 else
326 {
327 0 globus_gsi_cred_handle_destroy(entry->credential);
328 }
329
330 0 globus_free(entry);
331 }
332
333 0 return result;
334 }
335
336 void
337 globus_i_handler_wsse_pkipath_entry_destroy(
338 void * arg)
339 0 {
340 0 globus_i_handler_wsse_pkipath_entry_t * entry = arg;
341 0 if(entry)
342 {
343 0 if(entry->pkipath_buffer)
344 {
345 0 globus_free(entry->pkipath_buffer);
346 }
347
348 0 if(entry->credential)
349 {
350 0 globus_gsi_cred_handle_destroy(
351 entry->credential);
352 }
353
354 0 globus_free(entry);
355 }
356 0 }
357
358 globus_result_t
359 globus_i_handler_wsse_load_local_cred(
360 globus_soap_message_handle_t message_handle,
361 globus_gsi_cred_handle_t * credential,
362 char ** pkipath,
363 int * pkipath_length)
364 0 {
365 0 globus_gsi_cred_handle_t user_cred = NULL;
366 0 globus_result_t result = GLOBUS_SUCCESS;
367 unsigned long hash;
368 0 int user_cred_initialized = 0;
369 0 X509_NAME * x509n = NULL;
370
371
372 0 user_cred = globus_soap_message_handle_get_attr(
373 message_handle,
374 GLOBUS_HANDLER_WSSE_USER_CREDENTIAL_KEY);
375 0 if(!user_cred)
376 {
377 char * desired_subject;
378
379 0 desired_subject =
380 globus_soap_message_handle_get_attr(
381 message_handle,
382 GLOBUS_HANDLER_WSSE_DESIRED_SUBJECT_KEY);
383
384 0 if(desired_subject)
385 {
386 0 x509n = X509_NAME_new();
387 0 result = globus_gsi_cert_utils_get_x509_name(
388 desired_subject, strlen(desired_subject), x509n);
389 0 if(result != GLOBUS_SUCCESS)
390 {
391 0 result = GlobusWSSEErrorPKIPath(
392 result,
393 "Failed to get PKIPath from local user credential");
394 0 goto free_x509n;
395 }
396
397 0 globus_mutex_lock(&pkipath_table_mutex);
398 0 result = globus_i_handler_wsse_cache_lookup(
399 pkipath_table, X509_NAME_hash(x509n),
400 credential, pkipath, pkipath_length);
401 0 if(result == GLOBUS_SUCCESS)
402 {
403 0 globus_mutex_unlock(&pkipath_table_mutex);
404 0 goto free_x509n;
405 }
406 0 globus_mutex_unlock(&pkipath_table_mutex);
407 }
408
409 0 globus_mutex_lock(&pkipath_table_mutex);
410 0 if(cached_hash != 0)
411 {
412 0 result = globus_i_handler_wsse_cache_lookup(
413 pkipath_table, cached_hash,
414 credential, pkipath, pkipath_length);
415 0 if(result == GLOBUS_SUCCESS)
416 {
417 0 globus_mutex_unlock(&pkipath_table_mutex);
418 0 goto exit;
419 }
420 }
421 0 globus_mutex_unlock(&pkipath_table_mutex);
422
423 0 user_cred_initialized = 1;
424 0 result = globus_gsi_cred_handle_init(&user_cred, NULL);
425 0 if(result != GLOBUS_SUCCESS)
426 {
427 0 result = GlobusWSSEErrorPKIPath(
428 result, "Failed to load local user credential");
429 0 goto free_x509n;
430 }
431
432 0 result = globus_gsi_cred_read(user_cred, x509n);
433 0 if(result != GLOBUS_SUCCESS)
434 {
435 0 result = GlobusWSSEErrorPKIPath(
436 result, "Failed to load local user credential");
437 0 goto free_handle;
438 }
439
440 0 globus_mutex_lock(&pkipath_table_mutex);
441 0 result = globus_i_handler_wsse_cache_insert(
442 pkipath_table,
443 user_cred,
444 &hash);
445 0 if(result != GLOBUS_SUCCESS)
446 {
447 0 globus_mutex_unlock(&pkipath_table_mutex);
448 0 result = GlobusWSSEErrorPKIPath(
449 result, "Failed to insert user credential into cache");
450 0 goto free_handle;
451 }
452
453 0 result = globus_i_handler_wsse_cache_lookup(
454 pkipath_table,
455 hash,
456 credential,
457 pkipath,
458 pkipath_length);
459 0 if(result == GLOBUS_SUCCESS)
460 {
461 0 globus_mutex_unlock(&pkipath_table_mutex);
462 0 cached_hash = hash;
463 0 goto free_handle;
464 }
465 0 globus_mutex_unlock(&pkipath_table_mutex);
466 }
467 else
468 {
469 0 result = globus_gsi_cred_get_X509_subject_name(user_cred, &x509n);
470 0 if(result != GLOBUS_SUCCESS)
471 {
472 0 result = GlobusWSSEErrorPKIPath(
473 result, "Failed to load user cred");
474 0 goto free_handle;
475 }
476
477 0 globus_mutex_lock(&pkipath_table_mutex);
478 0 result = globus_i_handler_wsse_cache_lookup(
479 pkipath_table,
480 X509_NAME_hash(x509n),
481 credential,
482 pkipath,
483 pkipath_length);
484 0 if(result == GLOBUS_SUCCESS)
485 {
486 0 globus_mutex_unlock(&pkipath_table_mutex);
487 0 goto free_handle;
488 }
489 0 globus_mutex_unlock(&pkipath_table_mutex);
490 }
491
492 0 globus_mutex_lock(&pkipath_table_mutex);
493 0 result = globus_i_handler_wsse_cache_insert(
494 pkipath_table,
495 user_cred,
496 &hash);
497 0 if(result != GLOBUS_SUCCESS)
498 {
499 0 globus_mutex_unlock(&pkipath_table_mutex);
500 0 result = GlobusWSSEErrorPKIPath(
501 result, "Failed to insert credential into cache");
502 0 goto free_handle;
503 }
504
505 0 result = globus_i_handler_wsse_cache_lookup(
506 pkipath_table,
507 hash,
508 credential,
509 pkipath,
510 pkipath_length);
511 0 if(result != GLOBUS_SUCCESS)
512 {
513 0 globus_mutex_unlock(&pkipath_table_mutex);
514 0 result = GlobusWSSEErrorPKIPath(
515 result, "Failed to get credential from cache");
516 0 goto free_handle;
517 }
518
519 0 globus_mutex_unlock(&pkipath_table_mutex);
520
521 0 free_handle:
522
523 0 if(user_cred_initialized && user_cred)
524 {
525 0 globus_gsi_cred_handle_destroy(user_cred);
526 }
527
528 0 free_x509n:
529
530 0 if(x509n)
531 {
532 0 X509_NAME_free(x509n);
533 }
534
535 0 exit:
536
537 0 return result;