xref: /freebsd/crypto/krb5/src/ccapi/lib/ccapi_context.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* ccapi/lib/ccapi_context.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.h"
27 
28 #include "k5-platform.h"
29 
30 #include "ccapi_ccache.h"
31 #include "ccapi_ccache_iterator.h"
32 #include "ccapi_string.h"
33 #include "ccapi_ipc.h"
34 #include "ccapi_context_change_time.h"
35 #include "ccapi_err.h"
36 
37 #include <CredentialsCache2.h>
38 
39 typedef struct cci_context_d {
40     cc_context_f *functions;
41 #if TARGET_OS_MAC
42     cc_context_f *vector_functions;
43 #endif
44     cci_identifier_t identifier;
45     cc_uint32 synchronized;
46     cc_time_t last_wait_for_change_time;
47 } *cci_context_t;
48 
49 /* ------------------------------------------------------------------------ */
50 
51 struct cci_context_d cci_context_initializer = {
52     NULL
53     VECTOR_FUNCTIONS_INITIALIZER,
54     NULL,
55     0,
56     0
57 };
58 
59 cc_context_f cci_context_f_initializer = {
60     ccapi_context_release,
61     ccapi_context_get_change_time,
62     ccapi_context_get_default_ccache_name,
63     ccapi_context_open_ccache,
64     ccapi_context_open_default_ccache,
65     ccapi_context_create_ccache,
66     ccapi_context_create_default_ccache,
67     ccapi_context_create_new_ccache,
68     ccapi_context_new_ccache_iterator,
69     ccapi_context_lock,
70     ccapi_context_unlock,
71     ccapi_context_compare,
72     ccapi_context_wait_for_change
73 };
74 
75 static cc_int32 cci_context_sync (cci_context_t in_context,
76                                   cc_uint32     in_launch);
77 
78 #ifdef TARGET_OS_MAC
79 #pragma mark -
80 #endif
81 
82 MAKE_INIT_FUNCTION(cci_process_init);
83 MAKE_FINI_FUNCTION(cci_process_fini);
84 
85 /* ------------------------------------------------------------------------ */
86 
cci_process_init(void)87 static int cci_process_init (void)
88 {
89     cc_int32 err = ccNoError;
90 
91     if (!err) {
92         err = cci_context_change_time_thread_init ();
93     }
94 
95     if (!err) {
96         err = cci_ipc_process_init ();
97     }
98 
99     if (!err) {
100         add_error_table (&et_CAPI_error_table);
101     }
102 
103     return err;
104 }
105 
106 /* ------------------------------------------------------------------------ */
107 
cci_process_fini(void)108 static void cci_process_fini (void)
109 {
110     if (!INITIALIZER_RAN (cci_process_init) || PROGRAM_EXITING ()) {
111 	return;
112     }
113 
114     remove_error_table(&et_CAPI_error_table);
115     cci_context_change_time_thread_fini ();
116 }
117 
118 
119 #ifdef TARGET_OS_MAC
120 #pragma mark -
121 #endif
122 
123 /* ------------------------------------------------------------------------ */
124 
cc_initialize(cc_context_t * out_context,cc_int32 in_version,cc_int32 * out_supported_version,char const ** out_vendor)125 cc_int32 cc_initialize (cc_context_t  *out_context,
126                         cc_int32       in_version,
127                         cc_int32      *out_supported_version,
128                         char const   **out_vendor)
129 {
130     cc_int32 err = ccNoError;
131     cci_context_t context = NULL;
132     static char *vendor_string = "MIT Kerberos CCAPI";
133 
134     if (!out_context) { err = cci_check_error (ccErrBadParam); }
135 
136     if (!err) {
137         err = CALL_INIT_FUNCTION (cci_process_init);
138     }
139 
140     if (!err) {
141         switch (in_version) {
142             case ccapi_version_2:
143             case ccapi_version_3:
144             case ccapi_version_4:
145             case ccapi_version_5:
146             case ccapi_version_6:
147             case ccapi_version_7:
148                 break;
149 
150             default:
151                 err = ccErrBadAPIVersion;
152                 break;
153         }
154     }
155 
156     if (!err) {
157         context = malloc (sizeof (*context));
158         if (context) {
159             *context = cci_context_initializer;
160         } else {
161             err = cci_check_error (ccErrNoMem);
162         }
163     }
164 
165     if (!err) {
166         context->functions = malloc (sizeof (*context->functions));
167         if (context->functions) {
168             *context->functions = cci_context_f_initializer;
169         } else {
170             err = cci_check_error (ccErrNoMem);
171         }
172     }
173 
174     if (!err) {
175         context->identifier = cci_identifier_uninitialized;
176 
177         *out_context = (cc_context_t) context;
178         context = NULL; /* take ownership */
179 
180         if (out_supported_version) {
181             *out_supported_version = ccapi_version_max;
182         }
183 
184         if (out_vendor) {
185             *out_vendor = vendor_string;
186         }
187     }
188 
189     ccapi_context_release ((cc_context_t) context);
190 
191     return cci_check_error (err);
192 }
193 
194 #ifdef TARGET_OS_MAC
195 #pragma mark -
196 #endif
197 
198 /* ------------------------------------------------------------------------ */
199 /*
200  * Currently does not need to talk to the server since the server must
201  * handle cleaning up resources from crashed clients anyway.
202  *
203  * NOTE: if server communication is ever added here, make sure that
204  * krb5_stdcc_shutdown calls an internal function which does not talk to the
205  * server.  krb5_stdcc_shutdown is called from thread fini functions and may
206  * crash talking to the server depending on what order the OS calls the fini
207  * functions (ie: if the ipc layer fini function is called first).
208  */
209 
ccapi_context_release(cc_context_t in_context)210 cc_int32 ccapi_context_release (cc_context_t in_context)
211 {
212     cc_int32 err = ccNoError;
213     cci_context_t context = (cci_context_t) in_context;
214 
215     if (!in_context) { err = ccErrBadParam; }
216 
217     if (!err) {
218         cci_identifier_release (context->identifier);
219         free (context->functions);
220         free (context);
221     }
222 
223     return err;
224 }
225 
226 /* ------------------------------------------------------------------------ */
227 
ccapi_context_get_change_time(cc_context_t in_context,cc_time_t * out_change_time)228 cc_int32 ccapi_context_get_change_time (cc_context_t  in_context,
229                                         cc_time_t    *out_change_time)
230 {
231     cc_int32 err = ccNoError;
232     cci_context_t context = (cci_context_t) in_context;
233     k5_ipc_stream reply = NULL;
234 
235     if (!in_context     ) { err = cci_check_error (ccErrBadParam); }
236     if (!out_change_time) { err = cci_check_error (ccErrBadParam); }
237 
238     if (!err) {
239         err = cci_context_sync (context, 0);
240     }
241 
242     if (!err) {
243         err =  cci_ipc_send_no_launch (cci_context_get_change_time_msg_id,
244                                        context->identifier,
245                                        NULL, &reply);
246     }
247 
248     if (!err && krb5int_ipc_stream_size (reply) > 0) {
249         cc_time_t change_time = 0;
250 
251         /* got a response from the server */
252         err = krb5int_ipc_stream_read_time (reply, &change_time);
253 
254         if (!err) {
255             err = cci_context_change_time_update (context->identifier,
256                                                   change_time);
257         }
258     }
259 
260     if (!err) {
261         err = cci_context_change_time_get (out_change_time);
262     }
263 
264     krb5int_ipc_stream_release (reply);
265 
266     return cci_check_error (err);
267 }
268 
269 /* ------------------------------------------------------------------------ */
270 
ccapi_context_wait_for_change(cc_context_t in_context)271 cc_int32 ccapi_context_wait_for_change (cc_context_t  in_context)
272 {
273     cc_int32 err = ccNoError;
274     cci_context_t context = (cci_context_t) in_context;
275     k5_ipc_stream request = NULL;
276     k5_ipc_stream reply = NULL;
277 
278     if (!in_context) { err = cci_check_error (ccErrBadParam); }
279 
280     if (!err) {
281         err = krb5int_ipc_stream_new (&request);
282     }
283 
284     if (!err) {
285         err = krb5int_ipc_stream_write_time (request, context->last_wait_for_change_time);
286     }
287 
288     if (!err) {
289         err = cci_context_sync (context, 1);
290     }
291 
292     if (!err) {
293         err = cci_ipc_send (cci_context_wait_for_change_msg_id,
294 			    context->identifier,
295 			    request,
296 			    &reply);
297     }
298 
299     if (!err) {
300         err = krb5int_ipc_stream_read_time (reply, &context->last_wait_for_change_time);
301     }
302 
303     krb5int_ipc_stream_release (request);
304     krb5int_ipc_stream_release (reply);
305 
306     return cci_check_error (err);
307 }
308 
309 /* ------------------------------------------------------------------------ */
310 
ccapi_context_get_default_ccache_name(cc_context_t in_context,cc_string_t * out_name)311 cc_int32 ccapi_context_get_default_ccache_name (cc_context_t  in_context,
312                                                 cc_string_t  *out_name)
313 {
314     cc_int32 err = ccNoError;
315     cci_context_t context = (cci_context_t) in_context;
316     k5_ipc_stream reply = NULL;
317     char *reply_name = NULL;
318     char *name = NULL;
319 
320     if (!in_context) { err = cci_check_error (ccErrBadParam); }
321     if (!out_name  ) { err = cci_check_error (ccErrBadParam); }
322 
323     if (!err) {
324         err = cci_context_sync (context, 0);
325     }
326 
327     if (!err) {
328         err =  cci_ipc_send_no_launch (cci_context_get_default_ccache_name_msg_id,
329                                        context->identifier,
330                                        NULL,
331                                        &reply);
332     }
333 
334     if (!err) {
335         if (krb5int_ipc_stream_size (reply) > 0) {
336             /* got a response from the server */
337             err = krb5int_ipc_stream_read_string (reply, &reply_name);
338 
339             if (!err) {
340                 name = reply_name;
341             }
342         } else {
343             name = k_cci_context_initial_ccache_name;
344         }
345     }
346 
347     if (!err) {
348         err = cci_string_new (out_name, name);
349     }
350 
351     krb5int_ipc_stream_release (reply);
352     krb5int_ipc_stream_free_string (reply_name);
353 
354     return cci_check_error (err);
355 }
356 
357 /* ------------------------------------------------------------------------ */
358 
ccapi_context_open_ccache(cc_context_t in_context,const char * in_name,cc_ccache_t * out_ccache)359 cc_int32 ccapi_context_open_ccache (cc_context_t  in_context,
360                                     const char   *in_name,
361                                     cc_ccache_t  *out_ccache)
362 {
363     cc_int32 err = ccNoError;
364     cci_context_t context = (cci_context_t) in_context;
365     k5_ipc_stream request = NULL;
366     k5_ipc_stream reply = NULL;
367     cci_identifier_t identifier = NULL;
368 
369     if (!in_context  ) { err = cci_check_error (ccErrBadParam); }
370     if (!in_name     ) { err = cci_check_error (ccErrBadParam); }
371     if (!out_ccache  ) { err = cci_check_error (ccErrBadParam); }
372 
373     if (!err) {
374         err = krb5int_ipc_stream_new (&request);
375     }
376 
377     if (!err) {
378         err = krb5int_ipc_stream_write_string (request, in_name);
379     }
380 
381     if (!err) {
382         err = cci_context_sync (context, 0);
383     }
384 
385     if (!err) {
386         err =  cci_ipc_send_no_launch (cci_context_open_ccache_msg_id,
387                                        context->identifier,
388                                        request,
389                                        &reply);
390     }
391 
392     if (!err && !(krb5int_ipc_stream_size (reply) > 0)) {
393         err = ccErrCCacheNotFound;
394     }
395 
396     if (!err) {
397         err = cci_identifier_read (&identifier, reply);
398     }
399 
400     if (!err) {
401         err = cci_ccache_new (out_ccache, identifier);
402     }
403 
404     cci_identifier_release (identifier);
405     krb5int_ipc_stream_release (reply);
406     krb5int_ipc_stream_release (request);
407 
408     return cci_check_error (err);
409 }
410 
411 /* ------------------------------------------------------------------------ */
412 
ccapi_context_open_default_ccache(cc_context_t in_context,cc_ccache_t * out_ccache)413 cc_int32 ccapi_context_open_default_ccache (cc_context_t  in_context,
414                                             cc_ccache_t  *out_ccache)
415 {
416     cc_int32 err = ccNoError;
417     cci_context_t context = (cci_context_t) in_context;
418     k5_ipc_stream reply = NULL;
419     cci_identifier_t identifier = NULL;
420 
421     if (!in_context) { err = cci_check_error (ccErrBadParam); }
422     if (!out_ccache) { err = cci_check_error (ccErrBadParam); }
423 
424     if (!err) {
425         err = cci_context_sync (context, 0);
426     }
427 
428     if (!err) {
429         err =  cci_ipc_send_no_launch (cci_context_open_default_ccache_msg_id,
430                                        context->identifier,
431                                        NULL,
432                                        &reply);
433     }
434 
435     if (!err && !(krb5int_ipc_stream_size (reply) > 0)) {
436         err = ccErrCCacheNotFound;
437     }
438 
439     if (!err) {
440         err = cci_identifier_read (&identifier, reply);
441     }
442 
443     if (!err) {
444         err = cci_ccache_new (out_ccache, identifier);
445     }
446 
447     cci_identifier_release (identifier);
448     krb5int_ipc_stream_release (reply);
449 
450     return cci_check_error (err);
451 }
452 
453 /* ------------------------------------------------------------------------ */
454 
ccapi_context_create_ccache(cc_context_t in_context,const char * in_name,cc_uint32 in_cred_vers,const char * in_principal,cc_ccache_t * out_ccache)455 cc_int32 ccapi_context_create_ccache (cc_context_t  in_context,
456                                       const char   *in_name,
457                                       cc_uint32     in_cred_vers,
458                                       const char   *in_principal,
459                                       cc_ccache_t  *out_ccache)
460 {
461     cc_int32 err = ccNoError;
462     cci_context_t context = (cci_context_t) in_context;
463     k5_ipc_stream request = NULL;
464     k5_ipc_stream reply = NULL;
465     cci_identifier_t identifier = NULL;
466 
467     if (!in_context  ) { err = cci_check_error (ccErrBadParam); }
468     if (!in_name     ) { err = cci_check_error (ccErrBadParam); }
469     if (!in_principal) { err = cci_check_error (ccErrBadParam); }
470     if (!out_ccache  ) { err = cci_check_error (ccErrBadParam); }
471 
472     if (!err) {
473         err = krb5int_ipc_stream_new (&request);
474     }
475 
476     if (!err) {
477         err = krb5int_ipc_stream_write_string (request, in_name);
478     }
479 
480     if (!err) {
481         err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);
482     }
483 
484     if (!err) {
485         err = krb5int_ipc_stream_write_string (request, in_principal);
486     }
487 
488     if (!err) {
489         err = cci_context_sync (context, 1);
490     }
491 
492     if (!err) {
493         err =  cci_ipc_send (cci_context_create_ccache_msg_id,
494                              context->identifier,
495                              request,
496                              &reply);
497     }
498 
499     if (!err) {
500         err = cci_identifier_read (&identifier, reply);
501     }
502 
503     if (!err) {
504         err = cci_ccache_new (out_ccache, identifier);
505     }
506 
507     cci_identifier_release (identifier);
508     krb5int_ipc_stream_release (reply);
509     krb5int_ipc_stream_release (request);
510 
511     return cci_check_error (err);
512 }
513 
514 /* ------------------------------------------------------------------------ */
515 
ccapi_context_create_default_ccache(cc_context_t in_context,cc_uint32 in_cred_vers,const char * in_principal,cc_ccache_t * out_ccache)516 cc_int32 ccapi_context_create_default_ccache (cc_context_t  in_context,
517                                               cc_uint32     in_cred_vers,
518                                               const char   *in_principal,
519                                               cc_ccache_t  *out_ccache)
520 {
521     cc_int32 err = ccNoError;
522     cci_context_t context = (cci_context_t) in_context;
523     k5_ipc_stream request = NULL;
524     k5_ipc_stream reply = NULL;
525     cci_identifier_t identifier = NULL;
526 
527     if (!in_context  ) { err = cci_check_error (ccErrBadParam); }
528     if (!in_principal) { err = cci_check_error (ccErrBadParam); }
529     if (!out_ccache  ) { err = cci_check_error (ccErrBadParam); }
530 
531     if (!err) {
532         err = krb5int_ipc_stream_new (&request);
533     }
534 
535     if (!err) {
536         err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);
537     }
538 
539     if (!err) {
540         err = krb5int_ipc_stream_write_string (request, in_principal);
541     }
542 
543     if (!err) {
544         err = cci_context_sync (context, 1);
545     }
546 
547     if (!err) {
548         err =  cci_ipc_send (cci_context_create_default_ccache_msg_id,
549                              context->identifier,
550                              request,
551                              &reply);
552     }
553 
554     if (!err) {
555         err = cci_identifier_read (&identifier, reply);
556     }
557 
558     if (!err) {
559         err = cci_ccache_new (out_ccache, identifier);
560     }
561 
562     cci_identifier_release (identifier);
563     krb5int_ipc_stream_release (reply);
564     krb5int_ipc_stream_release (request);
565 
566     return cci_check_error (err);
567 }
568 
569 /* ------------------------------------------------------------------------ */
570 
ccapi_context_create_new_ccache(cc_context_t in_context,cc_uint32 in_cred_vers,const char * in_principal,cc_ccache_t * out_ccache)571 cc_int32 ccapi_context_create_new_ccache (cc_context_t in_context,
572                                           cc_uint32    in_cred_vers,
573                                           const char  *in_principal,
574                                           cc_ccache_t *out_ccache)
575 {
576     cc_int32 err = ccNoError;
577     cci_context_t context = (cci_context_t) in_context;
578     k5_ipc_stream request = NULL;
579     k5_ipc_stream reply = NULL;
580     cci_identifier_t identifier = NULL;
581 
582     if (!in_context  ) { err = cci_check_error (ccErrBadParam); }
583     if (!in_principal) { err = cci_check_error (ccErrBadParam); }
584     if (!out_ccache  ) { err = cci_check_error (ccErrBadParam); }
585 
586     if (!err) {
587         err = krb5int_ipc_stream_new (&request);
588     }
589 
590     if (!err) {
591         err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);
592     }
593 
594     if (!err) {
595         err = krb5int_ipc_stream_write_string (request, in_principal);
596     }
597 
598     if (!err) {
599         err = cci_context_sync (context, 1);
600     }
601 
602     if (!err) {
603         err =  cci_ipc_send (cci_context_create_new_ccache_msg_id,
604                              context->identifier,
605                              request,
606                              &reply);
607     }
608 
609     if (!err) {
610         err = cci_identifier_read (&identifier, reply);
611     }
612 
613     if (!err) {
614         err = cci_ccache_new (out_ccache, identifier);
615     }
616 
617     cci_identifier_release (identifier);
618     krb5int_ipc_stream_release (reply);
619     krb5int_ipc_stream_release (request);
620 
621     return cci_check_error (err);
622 }
623 
624 /* ------------------------------------------------------------------------ */
625 
ccapi_context_new_ccache_iterator(cc_context_t in_context,cc_ccache_iterator_t * out_iterator)626 cc_int32 ccapi_context_new_ccache_iterator (cc_context_t          in_context,
627                                             cc_ccache_iterator_t *out_iterator)
628 {
629     cc_int32 err = ccNoError;
630     cci_context_t context = (cci_context_t) in_context;
631     k5_ipc_stream reply = NULL;
632     cci_identifier_t identifier = NULL;
633 
634     if (!in_context  ) { err = cci_check_error (ccErrBadParam); }
635     if (!out_iterator) { err = cci_check_error (ccErrBadParam); }
636 
637     if (!err) {
638         err = cci_context_sync (context, 0);
639     }
640 
641     if (!err) {
642         err =  cci_ipc_send_no_launch (cci_context_new_ccache_iterator_msg_id,
643                                        context->identifier,
644                                        NULL,
645                                        &reply);
646     }
647 
648     if (!err) {
649         if (krb5int_ipc_stream_size (reply) > 0) {
650             err = cci_identifier_read (&identifier, reply);
651         } else {
652             identifier = cci_identifier_uninitialized;
653         }
654     }
655 
656     if (!err) {
657         err = cci_ccache_iterator_new (out_iterator, identifier);
658     }
659 
660     krb5int_ipc_stream_release (reply);
661     cci_identifier_release (identifier);
662 
663     return cci_check_error (err);
664 }
665 
666 /* ------------------------------------------------------------------------ */
667 
ccapi_context_lock(cc_context_t in_context,cc_uint32 in_lock_type,cc_uint32 in_block)668 cc_int32 ccapi_context_lock (cc_context_t in_context,
669                              cc_uint32    in_lock_type,
670                              cc_uint32    in_block)
671 {
672     cc_int32 err = ccNoError;
673     cci_context_t context = (cci_context_t) in_context;
674     k5_ipc_stream request = NULL;
675 
676     if (!in_context) { err = cci_check_error (ccErrBadParam); }
677 
678     if (!err) {
679         err = krb5int_ipc_stream_new (&request);
680     }
681 
682     if (!err) {
683         err = krb5int_ipc_stream_write_uint32 (request, in_lock_type);
684     }
685 
686     if (!err) {
687         err = krb5int_ipc_stream_write_uint32 (request, in_block);
688     }
689 
690     if (!err) {
691         err = cci_context_sync (context, 1);
692     }
693 
694     if (!err) {
695         err =  cci_ipc_send (cci_context_lock_msg_id,
696                              context->identifier,
697                              request,
698                              NULL);
699     }
700 
701     krb5int_ipc_stream_release (request);
702 
703     return cci_check_error (err);
704 }
705 
706 /* ------------------------------------------------------------------------ */
707 
ccapi_context_unlock(cc_context_t in_context)708 cc_int32 ccapi_context_unlock (cc_context_t in_context)
709 {
710     cc_int32 err = ccNoError;
711     cci_context_t context = (cci_context_t) in_context;
712 
713     if (!in_context) { err = cci_check_error (ccErrBadParam); }
714 
715     if (!err) {
716         err = cci_context_sync (context, 1);
717     }
718 
719     if (!err) {
720         err =  cci_ipc_send (cci_context_unlock_msg_id,
721                              context->identifier,
722                              NULL,
723                              NULL);
724     }
725 
726     return cci_check_error (err);
727 }
728 
729 /* ------------------------------------------------------------------------ */
730 
ccapi_context_compare(cc_context_t in_context,cc_context_t in_compare_to_context,cc_uint32 * out_equal)731 cc_int32 ccapi_context_compare (cc_context_t  in_context,
732                                 cc_context_t  in_compare_to_context,
733                                 cc_uint32    *out_equal)
734 {
735     cc_int32 err = ccNoError;
736     cci_context_t context = (cci_context_t) in_context;
737     cci_context_t compare_to_context = (cci_context_t) in_compare_to_context;
738 
739     if (!in_context           ) { err = cci_check_error (ccErrBadParam); }
740     if (!in_compare_to_context) { err = cci_check_error (ccErrBadParam); }
741     if (!out_equal            ) { err = cci_check_error (ccErrBadParam); }
742 
743     if (!err) {
744         err = cci_context_sync (context, 0);
745     }
746 
747     if (!err) {
748         err = cci_context_sync (compare_to_context, 0);
749     }
750 
751     if (!err) {
752         /* If both contexts can't talk to the server, then
753          * we assume they are equivalent */
754         err = cci_identifier_compare (context->identifier,
755                                       compare_to_context->identifier,
756                                       out_equal);
757     }
758 
759     return cci_check_error (err);
760 }
761 
762 #ifdef TARGET_OS_MAC
763 #pragma mark -
764 #endif
765 
766 /* ------------------------------------------------------------------------ */
767 
cci_context_sync(cci_context_t in_context,cc_uint32 in_launch)768 static cc_int32 cci_context_sync (cci_context_t in_context,
769                                   cc_uint32     in_launch)
770 {
771     cc_int32 err = ccNoError;
772     cci_context_t context = (cci_context_t) in_context;
773     k5_ipc_stream reply = NULL;
774     cci_identifier_t new_identifier = NULL;
775 
776     if (!in_context) { err = cci_check_error (ccErrBadParam); }
777 
778     if (!err) {
779         /* Use the uninitialized identifier because we may be talking  */
780         /* to a different server which would reject our identifier and */
781         /* the point of this message is to sync with the server's id   */
782         if (in_launch) {
783             err =  cci_ipc_send (cci_context_sync_msg_id,
784                                  cci_identifier_uninitialized,
785                                  NULL,
786                                  &reply);
787         } else {
788             err =  cci_ipc_send_no_launch (cci_context_sync_msg_id,
789                                            cci_identifier_uninitialized,
790                                            NULL,
791                                            &reply);
792         }
793     }
794 
795     if (!err) {
796         if (krb5int_ipc_stream_size (reply) > 0) {
797             err = cci_identifier_read (&new_identifier, reply);
798         } else {
799             new_identifier = cci_identifier_uninitialized;
800         }
801     }
802 
803     if (!err) {
804         cc_uint32 equal = 0;
805 
806         err = cci_identifier_compare (context->identifier, new_identifier, &equal);
807 
808         if (!err && !equal) {
809             if (context->identifier) {
810                 cci_identifier_release (context->identifier);
811             }
812             context->identifier = new_identifier;
813             new_identifier = NULL;  /* take ownership */
814         }
815     }
816 
817     if (!err && context->synchronized) {
818         err = cci_context_change_time_sync (context->identifier);
819     }
820 
821     if (!err && !context->synchronized) {
822         /* Keep state about whether this is the first call to avoid always   */
823         /* modifying the global change time on the context's first ipc call. */
824         context->synchronized = 1;
825     }
826 
827     cci_identifier_release (new_identifier);
828     krb5int_ipc_stream_release (reply);
829 
830     return cci_check_error (err);
831 }
832