1 /* ccapi/server/ccs_cache_collection.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 "k5-platform.h"	/* pull in asprintf decl/defn */
27 #include "ccs_common.h"
28 #include "ccs_os_notify.h"
29 
30 struct ccs_cache_collection_d {
31     cc_time_t last_changed_time;
32     cc_uint64 next_unique_name;
33     cci_identifier_t identifier;
34     ccs_lock_state_t lock_state;
35     ccs_ccache_list_t ccaches;
36     ccs_callback_array_t change_callbacks;
37 };
38 
39 struct ccs_cache_collection_d ccs_cache_collection_initializer = { 0, 0, NULL, NULL, NULL, NULL };
40 
41 /* ------------------------------------------------------------------------ */
42 
ccs_cache_collection_new(ccs_cache_collection_t * out_cache_collection)43 cc_int32 ccs_cache_collection_new (ccs_cache_collection_t *out_cache_collection)
44 {
45     cc_int32 err = ccNoError;
46     ccs_cache_collection_t cache_collection = NULL;
47 
48     if (!out_cache_collection) { err = cci_check_error (ccErrBadParam); }
49 
50     if (!err) {
51         cache_collection = malloc (sizeof (*cache_collection));
52         if (cache_collection) {
53             *cache_collection = ccs_cache_collection_initializer;
54         } else {
55             err = cci_check_error (ccErrNoMem);
56         }
57     }
58 
59     if (!err) {
60         err = ccs_server_new_identifier (&cache_collection->identifier);
61     }
62 
63     if (!err) {
64         err = ccs_lock_state_new (&cache_collection->lock_state,
65                                   ccErrInvalidContext,
66                                   ccErrContextLocked,
67                                   ccErrContextUnlocked);
68     }
69 
70     if (!err) {
71         err = ccs_ccache_list_new (&cache_collection->ccaches);
72     }
73 
74     if (!err) {
75         err = ccs_callback_array_new (&cache_collection->change_callbacks);
76     }
77 
78     if (!err) {
79         err = ccs_cache_collection_changed (cache_collection);
80     }
81 
82     if (!err) {
83         *out_cache_collection = cache_collection;
84         cache_collection = NULL;
85     }
86 
87     ccs_cache_collection_release (cache_collection);
88 
89     return cci_check_error (err);
90 }
91 
92 /* ------------------------------------------------------------------------ */
93 
ccs_cache_collection_release(ccs_cache_collection_t io_cache_collection)94 cc_int32 ccs_cache_collection_release (ccs_cache_collection_t io_cache_collection)
95 {
96     cc_int32 err = ccNoError;
97 
98     if (!err && io_cache_collection) {
99         cci_identifier_release (io_cache_collection->identifier);
100         ccs_lock_state_release (io_cache_collection->lock_state);
101         ccs_ccache_list_release (io_cache_collection->ccaches);
102         ccs_callback_array_release (io_cache_collection->change_callbacks);
103         free (io_cache_collection);
104     }
105 
106     return cci_check_error (err);
107 }
108 
109 /* ------------------------------------------------------------------------ */
110 
ccs_cache_collection_compare_identifier(ccs_cache_collection_t in_cache_collection,cci_identifier_t in_identifier,cc_uint32 * out_equal)111 cc_int32 ccs_cache_collection_compare_identifier (ccs_cache_collection_t  in_cache_collection,
112                                                   cci_identifier_t        in_identifier,
113                                                   cc_uint32              *out_equal)
114 {
115     cc_int32 err = ccNoError;
116 
117     if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
118     if (!in_identifier      ) { err = cci_check_error (ccErrBadParam); }
119     if (!out_equal          ) { err = cci_check_error (ccErrBadParam); }
120 
121     if (!err) {
122         err = cci_identifier_compare (in_cache_collection->identifier,
123                                       in_identifier,
124                                       out_equal);
125     }
126 
127     return cci_check_error (err);
128 }
129 
130 #ifdef TARGET_OS_MAC
131 #pragma mark -
132 #endif
133 
134 /* ------------------------------------------------------------------------ */
135 
ccs_cache_collection_changed(ccs_cache_collection_t io_cache_collection)136 cc_int32 ccs_cache_collection_changed (ccs_cache_collection_t io_cache_collection)
137 {
138     cc_int32 err = ccNoError;
139     k5_ipc_stream reply_data = NULL;
140 
141     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
142 
143     if (!err) {
144         cc_time_t now = time (NULL);
145 
146         if (io_cache_collection->last_changed_time < now) {
147             io_cache_collection->last_changed_time = now;
148         } else {
149             io_cache_collection->last_changed_time++;
150         }
151     }
152 
153     if (!err) {
154         err = krb5int_ipc_stream_new (&reply_data);
155     }
156 
157     if (!err) {
158 	err = krb5int_ipc_stream_write_time (reply_data, io_cache_collection->last_changed_time);
159     }
160 
161     if (!err) {
162 	/* Loop over callbacks sending messages to them */
163 	cc_uint64 i;
164         cc_uint64 count = ccs_callback_array_count (io_cache_collection->change_callbacks);
165 
166         for (i = 0; !err && i < count; i++) {
167             ccs_callback_t callback = ccs_callback_array_object_at_index (io_cache_collection->change_callbacks, i);
168 
169 	    err = ccs_callback_reply_to_client (callback, reply_data);
170 
171 	    if (!err) {
172 		cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
173 		err = ccs_callback_array_remove (io_cache_collection->change_callbacks, i);
174 		break;
175 	    }
176         }
177     }
178 
179     if (!err) {
180         err = ccs_os_notify_cache_collection_changed (io_cache_collection);
181     }
182 
183     krb5int_ipc_stream_release (reply_data);
184 
185     return cci_check_error (err);
186 }
187 
188 /* ------------------------------------------------------------------------ */
189 
ccs_cache_collection_invalidate_change_callback(ccs_callback_owner_t io_cache_collection,ccs_callback_t in_callback)190 static cc_int32 ccs_cache_collection_invalidate_change_callback (ccs_callback_owner_t io_cache_collection,
191 								 ccs_callback_t       in_callback)
192 {
193     cc_int32 err = ccNoError;
194 
195     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
196     if (!in_callback        ) { err = cci_check_error (ccErrBadParam); }
197 
198     if (!err) {
199 	/* Remove callback */
200 	ccs_cache_collection_t cache_collection = (ccs_cache_collection_t) io_cache_collection;
201 	cc_uint64 i;
202         cc_uint64 count = ccs_callback_array_count (cache_collection->change_callbacks);
203 
204         for (i = 0; !err && i < count; i++) {
205             ccs_callback_t callback = ccs_callback_array_object_at_index (cache_collection->change_callbacks, i);
206 
207 	    if (callback == in_callback) {
208 		cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
209 		err = ccs_callback_array_remove (cache_collection->change_callbacks, i);
210 		break;
211 	    }
212         }
213     }
214 
215     return cci_check_error (err);
216 }
217 
218 #ifdef TARGET_OS_MAC
219 #pragma mark -
220 #endif
221 
222 /* ------------------------------------------------------------------------ */
223 
ccs_cache_collection_find_ccache_by_name(ccs_cache_collection_t in_cache_collection,const char * in_name,ccs_ccache_t * out_ccache)224 static cc_int32 ccs_cache_collection_find_ccache_by_name (ccs_cache_collection_t  in_cache_collection,
225                                                           const char             *in_name,
226                                                           ccs_ccache_t           *out_ccache)
227 {
228     cc_int32 err = ccNoError;
229     ccs_ccache_list_iterator_t iterator = NULL;
230 
231     if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
232     if (!in_name            ) { err = cci_check_error (ccErrBadParam); }
233     if (!out_ccache         ) { err = cci_check_error (ccErrBadParam); }
234 
235     if (!err) {
236         err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
237                                             CCS_PIPE_NULL,
238                                             &iterator);
239     }
240 
241     while (!err) {
242         ccs_ccache_t ccache = NULL;
243 
244         err = ccs_ccache_list_iterator_next (iterator, &ccache);
245 
246         if (!err) {
247             cc_uint32 equal = 0;
248 
249             err = ccs_ccache_compare_name (ccache, in_name, &equal);
250 
251             if (!err && equal) {
252                 *out_ccache = ccache;
253                 break;
254             }
255         }
256     }
257     if (err == ccIteratorEnd) { err = ccErrCCacheNotFound; }
258 
259     if (iterator) { ccs_ccache_list_iterator_release (iterator); }
260 
261     return cci_check_error (err);
262 }
263 
264 #ifdef TARGET_OS_MAC
265 #pragma mark -
266 #endif
267 
268 /* ------------------------------------------------------------------------ */
269 
ccs_cache_collection_find_ccache(ccs_cache_collection_t in_cache_collection,cci_identifier_t in_identifier,ccs_ccache_t * out_ccache)270 cc_int32 ccs_cache_collection_find_ccache (ccs_cache_collection_t  in_cache_collection,
271                                            cci_identifier_t        in_identifier,
272                                            ccs_ccache_t           *out_ccache)
273 {
274     cc_int32 err = ccNoError;
275 
276     if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
277     if (!in_identifier      ) { err = cci_check_error (ccErrBadParam); }
278     if (!out_ccache         ) { err = cci_check_error (ccErrBadParam); }
279 
280     if (!err) {
281         err = ccs_ccache_list_find (in_cache_collection->ccaches,
282                                     in_identifier, out_ccache);
283     }
284 
285     return cci_check_error (err);
286 }
287 
288 /* ------------------------------------------------------------------------ */
289 
ccs_ccache_collection_move_ccache(ccs_cache_collection_t io_cache_collection,cci_identifier_t in_source_identifier,ccs_ccache_t io_destination_ccache)290 cc_int32 ccs_ccache_collection_move_ccache (ccs_cache_collection_t io_cache_collection,
291                                             cci_identifier_t       in_source_identifier,
292                                             ccs_ccache_t           io_destination_ccache)
293 {
294     cc_int32 err = ccNoError;
295     ccs_ccache_t source_ccache = NULL;
296 
297     if (!io_cache_collection  ) { err = cci_check_error (ccErrBadParam); }
298     if (!in_source_identifier ) { err = cci_check_error (ccErrBadParam); }
299     if (!io_destination_ccache) { err = cci_check_error (ccErrBadParam); }
300 
301     if (!err) {
302         err = ccs_cache_collection_find_ccache (io_cache_collection,
303                                                 in_source_identifier,
304                                                 &source_ccache);
305     }
306 
307     if (!err) {
308         err = ccs_ccache_swap_contents (source_ccache,
309 					io_destination_ccache,
310 					io_cache_collection);
311     }
312 
313     if (!err) {
314         err = ccs_cache_collection_destroy_ccache (io_cache_collection,
315                                                    in_source_identifier);
316     }
317 
318     return cci_check_error (err);
319 }
320 
321 /* ------------------------------------------------------------------------ */
322 
ccs_cache_collection_destroy_ccache(ccs_cache_collection_t io_cache_collection,cci_identifier_t in_identifier)323 cc_int32 ccs_cache_collection_destroy_ccache (ccs_cache_collection_t  io_cache_collection,
324                                               cci_identifier_t        in_identifier)
325 {
326     cc_int32 err = ccNoError;
327     ccs_ccache_t ccache = NULL;
328 
329     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
330     if (!in_identifier      ) { err = cci_check_error (ccErrBadParam); }
331 
332     if (!err) {
333         err = ccs_cache_collection_find_ccache (io_cache_collection,
334                                                 in_identifier,
335                                                 &ccache);
336     }
337 
338     if (!err) {
339         /* Notify before deletion because after deletion the ccache
340          * will no longer exist (and won't know about its clients) */
341         err = ccs_ccache_changed (ccache, io_cache_collection);
342     }
343 
344     if (!err) {
345         err = ccs_ccache_list_remove (io_cache_collection->ccaches,
346                                       in_identifier);
347     }
348 
349     return cci_check_error (err);
350 }
351 
352 #ifdef TARGET_OS_MAC
353 #pragma mark -
354 #endif
355 
356 /* ------------------------------------------------------------------------ */
357 
ccs_cache_collection_find_ccache_iterator(ccs_cache_collection_t in_cache_collection,cci_identifier_t in_identifier,ccs_ccache_iterator_t * out_ccache_iterator)358 cc_int32 ccs_cache_collection_find_ccache_iterator (ccs_cache_collection_t  in_cache_collection,
359                                                     cci_identifier_t        in_identifier,
360                                                     ccs_ccache_iterator_t  *out_ccache_iterator)
361 {
362     cc_int32 err = ccNoError;
363 
364     if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
365     if (!in_identifier      ) { err = cci_check_error (ccErrBadParam); }
366     if (!out_ccache_iterator) { err = cci_check_error (ccErrBadParam); }
367 
368     if (!err) {
369         err = ccs_ccache_list_find_iterator (in_cache_collection->ccaches,
370                                              in_identifier,
371                                              out_ccache_iterator);
372     }
373 
374     return cci_check_error (err);
375 }
376 
377 #ifdef TARGET_OS_MAC
378 #pragma mark -
379 #endif
380 
381 /* ------------------------------------------------------------------------ */
382 
ccs_cache_collection_find_credentials_iterator(ccs_cache_collection_t in_cache_collection,cci_identifier_t in_identifier,ccs_ccache_t * out_ccache,ccs_credentials_iterator_t * out_credentials_iterator)383 cc_int32 ccs_cache_collection_find_credentials_iterator (ccs_cache_collection_t      in_cache_collection,
384                                                          cci_identifier_t            in_identifier,
385                                                          ccs_ccache_t               *out_ccache,
386                                                          ccs_credentials_iterator_t *out_credentials_iterator)
387 {
388     cc_int32 err = ccNoError;
389     ccs_ccache_list_iterator_t iterator = NULL;
390 
391     if (!in_cache_collection     ) { err = cci_check_error (ccErrBadParam); }
392     if (!in_identifier           ) { err = cci_check_error (ccErrBadParam); }
393     if (!out_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
394 
395     if (!err) {
396         err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
397                                             CCS_PIPE_NULL,
398                                             &iterator);
399     }
400 
401     while (!err) {
402         ccs_ccache_t ccache = NULL;
403 
404         err = ccs_ccache_list_iterator_next (iterator, &ccache);
405 
406         if (!err) {
407             cc_int32 terr = ccs_ccache_find_credentials_iterator (ccache,
408                                                                   in_identifier,
409                                                                   out_credentials_iterator);
410             if (!terr) {
411                 *out_ccache = ccache;
412                 break;
413             }
414         }
415     }
416     if (err == ccIteratorEnd) { err = cci_check_error (ccErrInvalidCredentialsIterator); }
417 
418     if (iterator) { ccs_ccache_list_iterator_release (iterator); }
419 
420     return cci_check_error (err);
421 }
422 
423 #ifdef TARGET_OS_MAC
424 #pragma mark -
425 #endif
426 
427 /* ------------------------------------------------------------------------ */
428 
ccs_cache_collection_get_next_unique_ccache_name(ccs_cache_collection_t io_cache_collection,char ** out_name)429 static cc_int32 ccs_cache_collection_get_next_unique_ccache_name (ccs_cache_collection_t   io_cache_collection,
430                                                                   char                   **out_name)
431 {
432     cc_int32 err = ccNoError;
433     cc_uint64 count = 0;
434     char *name = NULL;
435 
436     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
437     if (!out_name           ) { err = cci_check_error (ccErrBadParam); }
438 
439     if (!err) {
440         err = ccs_cache_collection_list_count (io_cache_collection->ccaches, &count);
441     }
442 
443     if (!err) {
444         if (count > 0) {
445             while (!err) {
446                 int ret = asprintf (&name, "%lld", io_cache_collection->next_unique_name++);
447                 if (ret < 0 || !name) { err = cci_check_error (ccErrNoMem); }
448 
449                 if (!err) {
450                     ccs_ccache_t ccache = NULL;  /* temporary to hold ccache pointer */
451                     err = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
452                                                                     name, &ccache);
453                 }
454 
455                 if (err == ccErrCCacheNotFound) {
456                     err = ccNoError;
457                     break;   /* found a unique one */
458                 }
459             }
460         } else {
461             name = strdup (k_cci_context_initial_ccache_name);
462             if (!name) { err = cci_check_error (ccErrNoMem); }
463         }
464     }
465 
466     if (!err) {
467         *out_name = name;
468         name = NULL;
469     }
470 
471     free (name);
472 
473     return cci_check_error (err);
474 }
475 
476 /* ------------------------------------------------------------------------ */
477 
ccs_cache_collection_get_default_ccache(ccs_cache_collection_t in_cache_collection,ccs_ccache_t * out_ccache)478 static cc_int32 ccs_cache_collection_get_default_ccache (ccs_cache_collection_t  in_cache_collection,
479                                                          ccs_ccache_t           *out_ccache)
480 {
481     cc_int32 err = ccNoError;
482     cc_uint64 count = 0;
483 
484     if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
485     if (!out_ccache         ) { err = cci_check_error (ccErrBadParam); }
486 
487     if (!err) {
488         err = ccs_ccache_list_count (in_cache_collection->ccaches, &count);
489     }
490 
491     if (!err) {
492         if (count > 0) {
493             /* First ccache is the default */
494             ccs_ccache_list_iterator_t iterator = NULL;
495 
496             err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
497                                                 CCS_PIPE_NULL,
498                                                 &iterator);
499 
500             if (!err) {
501                 err = ccs_ccache_list_iterator_next (iterator, out_ccache);
502             }
503 
504             ccs_ccache_list_iterator_release (iterator);
505 
506         } else {
507             err = cci_check_error (ccErrCCacheNotFound);
508         }
509     }
510 
511     return cci_check_error (err);
512 }
513 
514 /* ------------------------------------------------------------------------ */
515 
ccs_cache_collection_set_default_ccache(ccs_cache_collection_t io_cache_collection,cci_identifier_t in_identifier)516 cc_int32 ccs_cache_collection_set_default_ccache (ccs_cache_collection_t  io_cache_collection,
517                                                   cci_identifier_t        in_identifier)
518 {
519     cc_int32 err = ccNoError;
520     ccs_ccache_t old_default = NULL;
521     ccs_ccache_t new_default = NULL;
522     cc_uint32 equal = 0;
523 
524     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
525     if (!in_identifier      ) { err = cci_check_error (ccErrBadParam); }
526 
527     if (!err) {
528         err = ccs_cache_collection_get_default_ccache (io_cache_collection,
529                                                        &old_default);
530     }
531 
532     if (!err) {
533 	err = ccs_ccache_compare_identifier (old_default, in_identifier, &equal);
534     }
535 
536 
537     if (!err && !equal) {
538         err = ccs_ccache_list_push_front (io_cache_collection->ccaches,
539                                           in_identifier);
540 
541 	if (!err) {
542 	    err = ccs_ccache_notify_default_state_changed (old_default,
543 							   io_cache_collection,
544 							   0 /* no longer default */);
545 	}
546 
547 	if (!err) {
548 	    err = ccs_cache_collection_get_default_ccache (io_cache_collection,
549 							   &new_default);
550 	}
551 
552 	if (!err) {
553 	    err = ccs_ccache_notify_default_state_changed (new_default,
554 							   io_cache_collection,
555 							   1 /* now default */);
556 	}
557 
558 	if (!err) {
559 	    err = ccs_cache_collection_changed (io_cache_collection);
560 	}
561     }
562 
563     return cci_check_error (err);
564 }
565 
566 #ifdef TARGET_OS_MAC
567 #pragma mark -
568 #pragma mark -- IPC Messages --
569 #endif
570 
571 /* ------------------------------------------------------------------------ */
572 
ccs_cache_collection_sync(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)573 static cc_int32 ccs_cache_collection_sync (ccs_cache_collection_t io_cache_collection,
574                                             k5_ipc_stream           in_request_data,
575                                             k5_ipc_stream           io_reply_data)
576 {
577     cc_int32 err = ccNoError;
578 
579     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
580     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
581     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
582 
583     if (!err) {
584         err = cci_identifier_write (io_cache_collection->identifier, io_reply_data);
585     }
586 
587     return cci_check_error (err);
588 }
589 
590 /* ------------------------------------------------------------------------ */
591 
ccs_cache_collection_get_change_time(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)592 static cc_int32 ccs_cache_collection_get_change_time (ccs_cache_collection_t io_cache_collection,
593                                                        k5_ipc_stream           in_request_data,
594                                                        k5_ipc_stream           io_reply_data)
595 {
596     cc_int32 err = ccNoError;
597 
598     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
599     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
600     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
601 
602     if (!err) {
603         err = krb5int_ipc_stream_write_time (io_reply_data, io_cache_collection->last_changed_time);
604     }
605 
606     return cci_check_error (err);
607 }
608 
609 /* ------------------------------------------------------------------------ */
610 
ccs_cache_collection_wait_for_change(ccs_pipe_t in_client_pipe,ccs_pipe_t in_reply_pipe,ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data,cc_uint32 * out_will_block)611 static cc_int32 ccs_cache_collection_wait_for_change (ccs_pipe_t              in_client_pipe,
612 						      ccs_pipe_t              in_reply_pipe,
613 						      ccs_cache_collection_t  io_cache_collection,
614 						      k5_ipc_stream            in_request_data,
615 						      k5_ipc_stream            io_reply_data,
616 						      cc_uint32              *out_will_block)
617 {
618     cc_int32 err = ccNoError;
619     cc_time_t last_wait_for_change_time = 0;
620     cc_uint32 will_block = 0;
621 
622     if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
623     if (!ccs_pipe_valid (in_reply_pipe )) { err = cci_check_error (ccErrBadParam); }
624     if (!io_cache_collection            ) { err = cci_check_error (ccErrBadParam); }
625     if (!in_request_data                ) { err = cci_check_error (ccErrBadParam); }
626     if (!out_will_block                 ) { err = cci_check_error (ccErrBadParam); }
627 
628     if (!err) {
629         err = krb5int_ipc_stream_read_time (in_request_data, &last_wait_for_change_time);
630     }
631 
632     if (!err) {
633 	if (last_wait_for_change_time < io_cache_collection->last_changed_time) {
634 	    err = krb5int_ipc_stream_write_time (io_reply_data, io_cache_collection->last_changed_time);
635 
636 	} else {
637 	    ccs_callback_t callback = NULL;
638 
639 	    err = ccs_callback_new (&callback,
640 				    ccErrInvalidContext,
641 				    in_client_pipe,
642 				    in_reply_pipe,
643 				    (ccs_callback_owner_t) io_cache_collection,
644 				    ccs_cache_collection_invalidate_change_callback);
645 
646 	    if (!err) {
647 		err = ccs_callback_array_insert (io_cache_collection->change_callbacks, callback,
648 						 ccs_callback_array_count (io_cache_collection->change_callbacks));
649 		if (!err) { callback = NULL; /* take ownership */ }
650 
651 		will_block = 1;
652 	    }
653 
654 	    ccs_callback_release (callback);
655 	}
656     }
657 
658     if (!err) {
659 	*out_will_block = will_block;
660     }
661 
662     return cci_check_error (err);
663 }
664 
665 /* ------------------------------------------------------------------------ */
666 
ccs_cache_collection_get_default_ccache_name(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)667 static cc_int32 ccs_cache_collection_get_default_ccache_name (ccs_cache_collection_t io_cache_collection,
668                                                                k5_ipc_stream           in_request_data,
669                                                                k5_ipc_stream           io_reply_data)
670 {
671     cc_int32 err = ccNoError;
672     cc_uint64 count = 0;
673 
674     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
675     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
676     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
677 
678     if (!err) {
679         err = ccs_cache_collection_list_count (io_cache_collection->ccaches, &count);
680     }
681 
682     if (!err) {
683         if (count > 0) {
684             ccs_ccache_t ccache = NULL;
685 
686             err = ccs_cache_collection_get_default_ccache (io_cache_collection, &ccache);
687 
688             if (!err) {
689                 err = ccs_ccache_write_name (ccache, io_reply_data);
690             }
691         } else {
692             err = krb5int_ipc_stream_write_string (io_reply_data,
693                                            k_cci_context_initial_ccache_name);
694         }
695     }
696 
697     return cci_check_error (err);
698 }
699 
700 /* ------------------------------------------------------------------------ */
701 
ccs_cache_collection_open_ccache(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)702 static cc_int32 ccs_cache_collection_open_ccache (ccs_cache_collection_t io_cache_collection,
703                                                    k5_ipc_stream           in_request_data,
704                                                    k5_ipc_stream           io_reply_data)
705 {
706     cc_int32 err = ccNoError;
707     char *name = NULL;
708     ccs_ccache_t ccache = NULL;
709 
710     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
711     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
712     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
713 
714     if (!err) {
715         err = krb5int_ipc_stream_read_string (in_request_data, &name);
716     }
717 
718     if (!err) {
719         err = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
720                                                         name, &ccache);
721     }
722 
723     if (!err) {
724         err = ccs_ccache_write (ccache, io_reply_data);
725     }
726 
727     krb5int_ipc_stream_free_string (name);
728 
729     return cci_check_error (err);
730 }
731 
732 /* ------------------------------------------------------------------------ */
733 
ccs_cache_collection_open_default_ccache(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)734 static cc_int32 ccs_cache_collection_open_default_ccache (ccs_cache_collection_t io_cache_collection,
735                                                            k5_ipc_stream           in_request_data,
736                                                            k5_ipc_stream           io_reply_data)
737 {
738     cc_int32 err = ccNoError;
739     ccs_ccache_t ccache = NULL;
740 
741     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
742     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
743     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
744 
745     if (!err) {
746          err = ccs_cache_collection_get_default_ccache (io_cache_collection,
747                                                         &ccache);
748     }
749 
750     if (!err) {
751         err = ccs_ccache_write (ccache, io_reply_data);
752     }
753 
754     return cci_check_error (err);
755 }
756 
757 /* ------------------------------------------------------------------------ */
758 
ccs_cache_collection_create_ccache(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)759 static cc_int32 ccs_cache_collection_create_ccache (ccs_cache_collection_t io_cache_collection,
760                                                     k5_ipc_stream           in_request_data,
761                                                     k5_ipc_stream           io_reply_data)
762 {
763     cc_int32 err = ccNoError;
764     char *name = NULL;
765     cc_uint32 cred_vers;
766     char *principal = NULL;
767     ccs_ccache_t ccache = NULL;
768 
769     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
770     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
771     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
772 
773     if (!err) {
774         err = krb5int_ipc_stream_read_string (in_request_data, &name);
775     }
776 
777     if (!err) {
778         err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
779     }
780 
781     if (!err) {
782         err = krb5int_ipc_stream_read_string (in_request_data, &principal);
783     }
784 
785     if (!err) {
786         cc_int32 terr = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
787                                                                   name,
788                                                                   &ccache);
789 
790         if (!terr) {
791             err = ccs_ccache_reset (ccache, io_cache_collection, cred_vers, principal);
792 
793         } else {
794             err = ccs_ccache_new (&ccache, cred_vers, name, principal,
795                                   io_cache_collection->ccaches);
796         }
797     }
798 
799     if (!err) {
800         err = ccs_ccache_write (ccache, io_reply_data);
801     }
802 
803     if (!err) {
804         err = ccs_cache_collection_changed (io_cache_collection);
805     }
806 
807     krb5int_ipc_stream_free_string (name);
808     krb5int_ipc_stream_free_string (principal);
809 
810     return cci_check_error (err);
811 }
812 
813 /* ------------------------------------------------------------------------ */
814 
ccs_cache_collection_create_default_ccache(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)815 static cc_int32 ccs_cache_collection_create_default_ccache (ccs_cache_collection_t io_cache_collection,
816                                                             k5_ipc_stream           in_request_data,
817                                                             k5_ipc_stream           io_reply_data)
818 {
819     cc_int32 err = ccNoError;
820     cc_uint32 cred_vers;
821     char *principal = NULL;
822     ccs_ccache_t ccache = NULL;
823 
824     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
825     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
826     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
827 
828     if (!err) {
829         err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
830     }
831 
832     if (!err) {
833         err = krb5int_ipc_stream_read_string (in_request_data, &principal);
834     }
835 
836     if (!err) {
837         err = ccs_cache_collection_get_default_ccache (io_cache_collection,
838                                                        &ccache);
839 
840         if (!err) {
841             err = ccs_ccache_reset (ccache, io_cache_collection, cred_vers, principal);
842 
843         } else if (err == ccErrCCacheNotFound) {
844             char *name = NULL;
845 
846             err = ccs_cache_collection_get_next_unique_ccache_name (io_cache_collection,
847                                                                     &name);
848 
849             if (!err) {
850                 err = ccs_ccache_new (&ccache, cred_vers, name, principal,
851                                       io_cache_collection->ccaches);
852             }
853 
854             free (name);
855         }
856     }
857 
858     if (!err) {
859         err = ccs_ccache_write (ccache, io_reply_data);
860     }
861 
862     if (!err) {
863         err = ccs_cache_collection_changed (io_cache_collection);
864     }
865 
866     krb5int_ipc_stream_free_string (principal);
867 
868     return cci_check_error (err);
869 }
870 
871 /* ------------------------------------------------------------------------ */
872 
ccs_cache_collection_create_new_ccache(ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)873 static cc_int32 ccs_cache_collection_create_new_ccache (ccs_cache_collection_t io_cache_collection,
874                                                         k5_ipc_stream           in_request_data,
875                                                         k5_ipc_stream           io_reply_data)
876 {
877     cc_int32 err = ccNoError;
878     cc_uint32 cred_vers;
879     char *principal = NULL;
880     char *name = NULL;
881     ccs_ccache_t ccache = NULL;
882 
883     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
884     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
885     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
886 
887     if (!err) {
888         err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
889     }
890 
891     if (!err) {
892         err = krb5int_ipc_stream_read_string (in_request_data, &principal);
893     }
894 
895     if (!err) {
896         err = ccs_cache_collection_get_next_unique_ccache_name (io_cache_collection,
897                                                                 &name);
898     }
899 
900     if (!err) {
901         err = ccs_ccache_new (&ccache, cred_vers, name, principal,
902                               io_cache_collection->ccaches);
903     }
904 
905     if (!err) {
906         err = ccs_ccache_write (ccache, io_reply_data);
907     }
908 
909     if (!err) {
910         err = ccs_cache_collection_changed (io_cache_collection);
911     }
912 
913     free (name);
914     krb5int_ipc_stream_free_string (principal);
915 
916     return cci_check_error (err);
917 }
918 
919 /* ------------------------------------------------------------------------ */
920 
ccs_cache_collection_new_ccache_iterator(ccs_cache_collection_t io_cache_collection,ccs_pipe_t in_client_pipe,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)921 static  cc_int32 ccs_cache_collection_new_ccache_iterator (ccs_cache_collection_t io_cache_collection,
922                                                            ccs_pipe_t             in_client_pipe,
923                                                            k5_ipc_stream           in_request_data,
924                                                            k5_ipc_stream           io_reply_data)
925 {
926     cc_int32 err = ccNoError;
927     ccs_ccache_iterator_t ccache_iterator = NULL;
928 
929     if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
930     if (!in_request_data    ) { err = cci_check_error (ccErrBadParam); }
931     if (!io_reply_data      ) { err = cci_check_error (ccErrBadParam); }
932 
933     if (!err) {
934         err = ccs_ccache_list_new_iterator (io_cache_collection->ccaches,
935                                             in_client_pipe,
936                                             &ccache_iterator);
937     }
938 
939     if (!err) {
940         err = ccs_ccache_list_iterator_write (ccache_iterator, io_reply_data);
941     }
942 
943     return cci_check_error (err);
944 }
945 
946 /* ------------------------------------------------------------------------ */
947 
ccs_cache_collection_lock(ccs_pipe_t in_client_pipe,ccs_pipe_t in_reply_pipe,ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,cc_uint32 * out_will_block,k5_ipc_stream io_reply_data)948 static cc_int32 ccs_cache_collection_lock (ccs_pipe_t              in_client_pipe,
949                                            ccs_pipe_t              in_reply_pipe,
950                                            ccs_cache_collection_t  io_cache_collection,
951                                            k5_ipc_stream            in_request_data,
952                                            cc_uint32              *out_will_block,
953                                            k5_ipc_stream            io_reply_data)
954 {
955     cc_int32 err = ccNoError;
956     cc_uint32 lock_type;
957     cc_uint32 block;
958 
959     if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
960     if (!io_cache_collection            ) { err = cci_check_error (ccErrBadParam); }
961     if (!in_request_data                ) { err = cci_check_error (ccErrBadParam); }
962     if (!out_will_block                 ) { err = cci_check_error (ccErrBadParam); }
963     if (!io_reply_data                  ) { err = cci_check_error (ccErrBadParam); }
964 
965     if (!err) {
966         err = krb5int_ipc_stream_read_uint32 (in_request_data, &lock_type);
967     }
968 
969     if (!err) {
970         err = krb5int_ipc_stream_read_uint32 (in_request_data, &block);
971     }
972 
973     if (!err) {
974         err = ccs_lock_state_add (io_cache_collection->lock_state,
975                                   in_client_pipe, in_reply_pipe,
976                                   lock_type, block, out_will_block);
977     }
978 
979     return cci_check_error (err);
980 }
981 
982 /* ------------------------------------------------------------------------ */
983 
ccs_cache_collection_unlock(ccs_pipe_t in_client_pipe,ccs_cache_collection_t io_cache_collection,k5_ipc_stream in_request_data,k5_ipc_stream io_reply_data)984 static cc_int32 ccs_cache_collection_unlock (ccs_pipe_t             in_client_pipe,
985                                              ccs_cache_collection_t io_cache_collection,
986                                              k5_ipc_stream           in_request_data,
987                                              k5_ipc_stream           io_reply_data)
988 {
989     cc_int32 err = ccNoError;
990 
991     if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
992     if (!io_cache_collection            ) { err = cci_check_error (ccErrBadParam); }
993     if (!in_request_data                ) { err = cci_check_error (ccErrBadParam); }
994     if (!io_reply_data                  ) { err = cci_check_error (ccErrBadParam); }
995 
996     if (!err) {
997         err = ccs_lock_state_remove (io_cache_collection->lock_state,
998                                      in_client_pipe);
999     }
1000 
1001     return cci_check_error (err);
1002 }
1003 
1004 #ifdef TARGET_OS_MAC
1005 #pragma mark -
1006 #endif
1007 
1008 /* ------------------------------------------------------------------------ */
1009 
ccs_cache_collection_handle_message(ccs_pipe_t in_client_pipe,ccs_pipe_t in_reply_pipe,ccs_cache_collection_t io_cache_collection,enum cci_msg_id_t in_request_name,k5_ipc_stream in_request_data,cc_uint32 * out_will_block,k5_ipc_stream * out_reply_data)1010  cc_int32 ccs_cache_collection_handle_message (ccs_pipe_t              in_client_pipe,
1011                                                ccs_pipe_t              in_reply_pipe,
1012                                                ccs_cache_collection_t  io_cache_collection,
1013                                                enum cci_msg_id_t       in_request_name,
1014                                                k5_ipc_stream            in_request_data,
1015                                                cc_uint32              *out_will_block,
1016                                                k5_ipc_stream           *out_reply_data)
1017 {
1018     cc_int32 err = ccNoError;
1019     cc_uint32 will_block = 0;
1020     k5_ipc_stream reply_data = NULL;
1021 
1022     if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
1023     if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
1024     if (!io_cache_collection            ) { err = cci_check_error (ccErrBadParam); }
1025     if (!in_request_data                ) { err = cci_check_error (ccErrBadParam); }
1026     if (!out_will_block                 ) { err = cci_check_error (ccErrBadParam); }
1027     if (!out_reply_data                 ) { err = cci_check_error (ccErrBadParam); }
1028 
1029     if (!err) {
1030         err = krb5int_ipc_stream_new (&reply_data);
1031     }
1032 
1033     if (!err) {
1034         if (in_request_name == cci_context_unused_release_msg_id) {
1035             /* Old release message.  Do nothing. */
1036 
1037         } else if (in_request_name == cci_context_sync_msg_id) {
1038             err = ccs_cache_collection_sync (io_cache_collection,
1039                                              in_request_data, reply_data);
1040 
1041         } else if (in_request_name == cci_context_get_change_time_msg_id) {
1042             err = ccs_cache_collection_get_change_time (io_cache_collection,
1043                                                         in_request_data, reply_data);
1044 
1045         } else if (in_request_name == cci_context_wait_for_change_msg_id) {
1046             err = ccs_cache_collection_wait_for_change (in_client_pipe, in_reply_pipe,
1047 							io_cache_collection,
1048                                                         in_request_data, reply_data,
1049 							&will_block);
1050 
1051         } else if (in_request_name == cci_context_get_default_ccache_name_msg_id) {
1052             err = ccs_cache_collection_get_default_ccache_name (io_cache_collection,
1053                                                                 in_request_data, reply_data);
1054 
1055         } else if (in_request_name == cci_context_open_ccache_msg_id) {
1056             err = ccs_cache_collection_open_ccache (io_cache_collection,
1057                                                     in_request_data, reply_data);
1058 
1059         } else if (in_request_name == cci_context_open_default_ccache_msg_id) {
1060             err = ccs_cache_collection_open_default_ccache (io_cache_collection,
1061                                                             in_request_data, reply_data);
1062 
1063         } else if (in_request_name == cci_context_create_ccache_msg_id) {
1064             err = ccs_cache_collection_create_ccache (io_cache_collection,
1065                                                       in_request_data, reply_data);
1066 
1067         } else if (in_request_name == cci_context_create_default_ccache_msg_id) {
1068             err = ccs_cache_collection_create_default_ccache (io_cache_collection,
1069                                                               in_request_data, reply_data);
1070 
1071         } else if (in_request_name == cci_context_create_new_ccache_msg_id) {
1072             err = ccs_cache_collection_create_new_ccache (io_cache_collection,
1073                                                           in_request_data, reply_data);
1074 
1075         } else if (in_request_name == cci_context_new_ccache_iterator_msg_id) {
1076             err = ccs_cache_collection_new_ccache_iterator (io_cache_collection,
1077                                                             in_client_pipe,
1078                                                             in_request_data,
1079                                                             reply_data);
1080 
1081         } else if (in_request_name == cci_context_lock_msg_id) {
1082             err = ccs_cache_collection_lock (in_client_pipe, in_reply_pipe,
1083                                              io_cache_collection,
1084                                              in_request_data,
1085                                              &will_block, reply_data);
1086 
1087         } else if (in_request_name == cci_context_unlock_msg_id) {
1088             err = ccs_cache_collection_unlock (in_client_pipe, io_cache_collection,
1089                                                in_request_data, reply_data);
1090 
1091         } else {
1092             err = ccErrBadInternalMessage;
1093         }
1094     }
1095 
1096     if (!err) {
1097         *out_will_block = will_block;
1098         if (!will_block) {
1099             *out_reply_data = reply_data;
1100             reply_data = NULL; /* take ownership */
1101         } else {
1102             *out_reply_data = NULL;
1103         }
1104     }
1105 
1106     krb5int_ipc_stream_release (reply_data);
1107 
1108     return cci_check_error (err);
1109 }
1110