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