Path: blob/main/crypto/krb5/src/ccapi/lib/ccapi_context.c
39536 views
/* ccapi/lib/ccapi_context.c */1/*2* Copyright 2006, 2007 Massachusetts Institute of Technology.3* All Rights Reserved.4*5* Export of this software from the United States of America may6* require a specific license from the United States Government.7* It is the responsibility of any person or organization contemplating8* export to obtain such a license before exporting.9*10* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and11* distribute this software and its documentation for any purpose and12* without fee is hereby granted, provided that the above copyright13* notice appear in all copies and that both that copyright notice and14* this permission notice appear in supporting documentation, and that15* the name of M.I.T. not be used in advertising or publicity pertaining16* to distribution of the software without specific, written prior17* permission. Furthermore if you modify this software you must label18* your software as modified software and not distribute it in such a19* fashion that it might be confused with the original M.I.T. software.20* M.I.T. makes no representations about the suitability of21* this software for any purpose. It is provided "as is" without express22* or implied warranty.23*/2425#include "ccapi_context.h"2627#include "k5-platform.h"2829#include "ccapi_ccache.h"30#include "ccapi_ccache_iterator.h"31#include "ccapi_string.h"32#include "ccapi_ipc.h"33#include "ccapi_context_change_time.h"34#include "ccapi_err.h"3536#include <CredentialsCache2.h>3738typedef struct cci_context_d {39cc_context_f *functions;40#if TARGET_OS_MAC41cc_context_f *vector_functions;42#endif43cci_identifier_t identifier;44cc_uint32 synchronized;45cc_time_t last_wait_for_change_time;46} *cci_context_t;4748/* ------------------------------------------------------------------------ */4950struct cci_context_d cci_context_initializer = {51NULL52VECTOR_FUNCTIONS_INITIALIZER,53NULL,540,55056};5758cc_context_f cci_context_f_initializer = {59ccapi_context_release,60ccapi_context_get_change_time,61ccapi_context_get_default_ccache_name,62ccapi_context_open_ccache,63ccapi_context_open_default_ccache,64ccapi_context_create_ccache,65ccapi_context_create_default_ccache,66ccapi_context_create_new_ccache,67ccapi_context_new_ccache_iterator,68ccapi_context_lock,69ccapi_context_unlock,70ccapi_context_compare,71ccapi_context_wait_for_change72};7374static cc_int32 cci_context_sync (cci_context_t in_context,75cc_uint32 in_launch);7677#ifdef TARGET_OS_MAC78#pragma mark -79#endif8081MAKE_INIT_FUNCTION(cci_process_init);82MAKE_FINI_FUNCTION(cci_process_fini);8384/* ------------------------------------------------------------------------ */8586static int cci_process_init (void)87{88cc_int32 err = ccNoError;8990if (!err) {91err = cci_context_change_time_thread_init ();92}9394if (!err) {95err = cci_ipc_process_init ();96}9798if (!err) {99add_error_table (&et_CAPI_error_table);100}101102return err;103}104105/* ------------------------------------------------------------------------ */106107static void cci_process_fini (void)108{109if (!INITIALIZER_RAN (cci_process_init) || PROGRAM_EXITING ()) {110return;111}112113remove_error_table(&et_CAPI_error_table);114cci_context_change_time_thread_fini ();115}116117118#ifdef TARGET_OS_MAC119#pragma mark -120#endif121122/* ------------------------------------------------------------------------ */123124cc_int32 cc_initialize (cc_context_t *out_context,125cc_int32 in_version,126cc_int32 *out_supported_version,127char const **out_vendor)128{129cc_int32 err = ccNoError;130cci_context_t context = NULL;131static char *vendor_string = "MIT Kerberos CCAPI";132133if (!out_context) { err = cci_check_error (ccErrBadParam); }134135if (!err) {136err = CALL_INIT_FUNCTION (cci_process_init);137}138139if (!err) {140switch (in_version) {141case ccapi_version_2:142case ccapi_version_3:143case ccapi_version_4:144case ccapi_version_5:145case ccapi_version_6:146case ccapi_version_7:147break;148149default:150err = ccErrBadAPIVersion;151break;152}153}154155if (!err) {156context = malloc (sizeof (*context));157if (context) {158*context = cci_context_initializer;159} else {160err = cci_check_error (ccErrNoMem);161}162}163164if (!err) {165context->functions = malloc (sizeof (*context->functions));166if (context->functions) {167*context->functions = cci_context_f_initializer;168} else {169err = cci_check_error (ccErrNoMem);170}171}172173if (!err) {174context->identifier = cci_identifier_uninitialized;175176*out_context = (cc_context_t) context;177context = NULL; /* take ownership */178179if (out_supported_version) {180*out_supported_version = ccapi_version_max;181}182183if (out_vendor) {184*out_vendor = vendor_string;185}186}187188ccapi_context_release ((cc_context_t) context);189190return cci_check_error (err);191}192193#ifdef TARGET_OS_MAC194#pragma mark -195#endif196197/* ------------------------------------------------------------------------ */198/*199* Currently does not need to talk to the server since the server must200* handle cleaning up resources from crashed clients anyway.201*202* NOTE: if server communication is ever added here, make sure that203* krb5_stdcc_shutdown calls an internal function which does not talk to the204* server. krb5_stdcc_shutdown is called from thread fini functions and may205* crash talking to the server depending on what order the OS calls the fini206* functions (ie: if the ipc layer fini function is called first).207*/208209cc_int32 ccapi_context_release (cc_context_t in_context)210{211cc_int32 err = ccNoError;212cci_context_t context = (cci_context_t) in_context;213214if (!in_context) { err = ccErrBadParam; }215216if (!err) {217cci_identifier_release (context->identifier);218free (context->functions);219free (context);220}221222return err;223}224225/* ------------------------------------------------------------------------ */226227cc_int32 ccapi_context_get_change_time (cc_context_t in_context,228cc_time_t *out_change_time)229{230cc_int32 err = ccNoError;231cci_context_t context = (cci_context_t) in_context;232k5_ipc_stream reply = NULL;233234if (!in_context ) { err = cci_check_error (ccErrBadParam); }235if (!out_change_time) { err = cci_check_error (ccErrBadParam); }236237if (!err) {238err = cci_context_sync (context, 0);239}240241if (!err) {242err = cci_ipc_send_no_launch (cci_context_get_change_time_msg_id,243context->identifier,244NULL, &reply);245}246247if (!err && krb5int_ipc_stream_size (reply) > 0) {248cc_time_t change_time = 0;249250/* got a response from the server */251err = krb5int_ipc_stream_read_time (reply, &change_time);252253if (!err) {254err = cci_context_change_time_update (context->identifier,255change_time);256}257}258259if (!err) {260err = cci_context_change_time_get (out_change_time);261}262263krb5int_ipc_stream_release (reply);264265return cci_check_error (err);266}267268/* ------------------------------------------------------------------------ */269270cc_int32 ccapi_context_wait_for_change (cc_context_t in_context)271{272cc_int32 err = ccNoError;273cci_context_t context = (cci_context_t) in_context;274k5_ipc_stream request = NULL;275k5_ipc_stream reply = NULL;276277if (!in_context) { err = cci_check_error (ccErrBadParam); }278279if (!err) {280err = krb5int_ipc_stream_new (&request);281}282283if (!err) {284err = krb5int_ipc_stream_write_time (request, context->last_wait_for_change_time);285}286287if (!err) {288err = cci_context_sync (context, 1);289}290291if (!err) {292err = cci_ipc_send (cci_context_wait_for_change_msg_id,293context->identifier,294request,295&reply);296}297298if (!err) {299err = krb5int_ipc_stream_read_time (reply, &context->last_wait_for_change_time);300}301302krb5int_ipc_stream_release (request);303krb5int_ipc_stream_release (reply);304305return cci_check_error (err);306}307308/* ------------------------------------------------------------------------ */309310cc_int32 ccapi_context_get_default_ccache_name (cc_context_t in_context,311cc_string_t *out_name)312{313cc_int32 err = ccNoError;314cci_context_t context = (cci_context_t) in_context;315k5_ipc_stream reply = NULL;316char *reply_name = NULL;317char *name = NULL;318319if (!in_context) { err = cci_check_error (ccErrBadParam); }320if (!out_name ) { err = cci_check_error (ccErrBadParam); }321322if (!err) {323err = cci_context_sync (context, 0);324}325326if (!err) {327err = cci_ipc_send_no_launch (cci_context_get_default_ccache_name_msg_id,328context->identifier,329NULL,330&reply);331}332333if (!err) {334if (krb5int_ipc_stream_size (reply) > 0) {335/* got a response from the server */336err = krb5int_ipc_stream_read_string (reply, &reply_name);337338if (!err) {339name = reply_name;340}341} else {342name = k_cci_context_initial_ccache_name;343}344}345346if (!err) {347err = cci_string_new (out_name, name);348}349350krb5int_ipc_stream_release (reply);351krb5int_ipc_stream_free_string (reply_name);352353return cci_check_error (err);354}355356/* ------------------------------------------------------------------------ */357358cc_int32 ccapi_context_open_ccache (cc_context_t in_context,359const char *in_name,360cc_ccache_t *out_ccache)361{362cc_int32 err = ccNoError;363cci_context_t context = (cci_context_t) in_context;364k5_ipc_stream request = NULL;365k5_ipc_stream reply = NULL;366cci_identifier_t identifier = NULL;367368if (!in_context ) { err = cci_check_error (ccErrBadParam); }369if (!in_name ) { err = cci_check_error (ccErrBadParam); }370if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }371372if (!err) {373err = krb5int_ipc_stream_new (&request);374}375376if (!err) {377err = krb5int_ipc_stream_write_string (request, in_name);378}379380if (!err) {381err = cci_context_sync (context, 0);382}383384if (!err) {385err = cci_ipc_send_no_launch (cci_context_open_ccache_msg_id,386context->identifier,387request,388&reply);389}390391if (!err && !(krb5int_ipc_stream_size (reply) > 0)) {392err = ccErrCCacheNotFound;393}394395if (!err) {396err = cci_identifier_read (&identifier, reply);397}398399if (!err) {400err = cci_ccache_new (out_ccache, identifier);401}402403cci_identifier_release (identifier);404krb5int_ipc_stream_release (reply);405krb5int_ipc_stream_release (request);406407return cci_check_error (err);408}409410/* ------------------------------------------------------------------------ */411412cc_int32 ccapi_context_open_default_ccache (cc_context_t in_context,413cc_ccache_t *out_ccache)414{415cc_int32 err = ccNoError;416cci_context_t context = (cci_context_t) in_context;417k5_ipc_stream reply = NULL;418cci_identifier_t identifier = NULL;419420if (!in_context) { err = cci_check_error (ccErrBadParam); }421if (!out_ccache) { err = cci_check_error (ccErrBadParam); }422423if (!err) {424err = cci_context_sync (context, 0);425}426427if (!err) {428err = cci_ipc_send_no_launch (cci_context_open_default_ccache_msg_id,429context->identifier,430NULL,431&reply);432}433434if (!err && !(krb5int_ipc_stream_size (reply) > 0)) {435err = ccErrCCacheNotFound;436}437438if (!err) {439err = cci_identifier_read (&identifier, reply);440}441442if (!err) {443err = cci_ccache_new (out_ccache, identifier);444}445446cci_identifier_release (identifier);447krb5int_ipc_stream_release (reply);448449return cci_check_error (err);450}451452/* ------------------------------------------------------------------------ */453454cc_int32 ccapi_context_create_ccache (cc_context_t in_context,455const char *in_name,456cc_uint32 in_cred_vers,457const char *in_principal,458cc_ccache_t *out_ccache)459{460cc_int32 err = ccNoError;461cci_context_t context = (cci_context_t) in_context;462k5_ipc_stream request = NULL;463k5_ipc_stream reply = NULL;464cci_identifier_t identifier = NULL;465466if (!in_context ) { err = cci_check_error (ccErrBadParam); }467if (!in_name ) { err = cci_check_error (ccErrBadParam); }468if (!in_principal) { err = cci_check_error (ccErrBadParam); }469if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }470471if (!err) {472err = krb5int_ipc_stream_new (&request);473}474475if (!err) {476err = krb5int_ipc_stream_write_string (request, in_name);477}478479if (!err) {480err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);481}482483if (!err) {484err = krb5int_ipc_stream_write_string (request, in_principal);485}486487if (!err) {488err = cci_context_sync (context, 1);489}490491if (!err) {492err = cci_ipc_send (cci_context_create_ccache_msg_id,493context->identifier,494request,495&reply);496}497498if (!err) {499err = cci_identifier_read (&identifier, reply);500}501502if (!err) {503err = cci_ccache_new (out_ccache, identifier);504}505506cci_identifier_release (identifier);507krb5int_ipc_stream_release (reply);508krb5int_ipc_stream_release (request);509510return cci_check_error (err);511}512513/* ------------------------------------------------------------------------ */514515cc_int32 ccapi_context_create_default_ccache (cc_context_t in_context,516cc_uint32 in_cred_vers,517const char *in_principal,518cc_ccache_t *out_ccache)519{520cc_int32 err = ccNoError;521cci_context_t context = (cci_context_t) in_context;522k5_ipc_stream request = NULL;523k5_ipc_stream reply = NULL;524cci_identifier_t identifier = NULL;525526if (!in_context ) { err = cci_check_error (ccErrBadParam); }527if (!in_principal) { err = cci_check_error (ccErrBadParam); }528if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }529530if (!err) {531err = krb5int_ipc_stream_new (&request);532}533534if (!err) {535err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);536}537538if (!err) {539err = krb5int_ipc_stream_write_string (request, in_principal);540}541542if (!err) {543err = cci_context_sync (context, 1);544}545546if (!err) {547err = cci_ipc_send (cci_context_create_default_ccache_msg_id,548context->identifier,549request,550&reply);551}552553if (!err) {554err = cci_identifier_read (&identifier, reply);555}556557if (!err) {558err = cci_ccache_new (out_ccache, identifier);559}560561cci_identifier_release (identifier);562krb5int_ipc_stream_release (reply);563krb5int_ipc_stream_release (request);564565return cci_check_error (err);566}567568/* ------------------------------------------------------------------------ */569570cc_int32 ccapi_context_create_new_ccache (cc_context_t in_context,571cc_uint32 in_cred_vers,572const char *in_principal,573cc_ccache_t *out_ccache)574{575cc_int32 err = ccNoError;576cci_context_t context = (cci_context_t) in_context;577k5_ipc_stream request = NULL;578k5_ipc_stream reply = NULL;579cci_identifier_t identifier = NULL;580581if (!in_context ) { err = cci_check_error (ccErrBadParam); }582if (!in_principal) { err = cci_check_error (ccErrBadParam); }583if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }584585if (!err) {586err = krb5int_ipc_stream_new (&request);587}588589if (!err) {590err = krb5int_ipc_stream_write_uint32 (request, in_cred_vers);591}592593if (!err) {594err = krb5int_ipc_stream_write_string (request, in_principal);595}596597if (!err) {598err = cci_context_sync (context, 1);599}600601if (!err) {602err = cci_ipc_send (cci_context_create_new_ccache_msg_id,603context->identifier,604request,605&reply);606}607608if (!err) {609err = cci_identifier_read (&identifier, reply);610}611612if (!err) {613err = cci_ccache_new (out_ccache, identifier);614}615616cci_identifier_release (identifier);617krb5int_ipc_stream_release (reply);618krb5int_ipc_stream_release (request);619620return cci_check_error (err);621}622623/* ------------------------------------------------------------------------ */624625cc_int32 ccapi_context_new_ccache_iterator (cc_context_t in_context,626cc_ccache_iterator_t *out_iterator)627{628cc_int32 err = ccNoError;629cci_context_t context = (cci_context_t) in_context;630k5_ipc_stream reply = NULL;631cci_identifier_t identifier = NULL;632633if (!in_context ) { err = cci_check_error (ccErrBadParam); }634if (!out_iterator) { err = cci_check_error (ccErrBadParam); }635636if (!err) {637err = cci_context_sync (context, 0);638}639640if (!err) {641err = cci_ipc_send_no_launch (cci_context_new_ccache_iterator_msg_id,642context->identifier,643NULL,644&reply);645}646647if (!err) {648if (krb5int_ipc_stream_size (reply) > 0) {649err = cci_identifier_read (&identifier, reply);650} else {651identifier = cci_identifier_uninitialized;652}653}654655if (!err) {656err = cci_ccache_iterator_new (out_iterator, identifier);657}658659krb5int_ipc_stream_release (reply);660cci_identifier_release (identifier);661662return cci_check_error (err);663}664665/* ------------------------------------------------------------------------ */666667cc_int32 ccapi_context_lock (cc_context_t in_context,668cc_uint32 in_lock_type,669cc_uint32 in_block)670{671cc_int32 err = ccNoError;672cci_context_t context = (cci_context_t) in_context;673k5_ipc_stream request = NULL;674675if (!in_context) { err = cci_check_error (ccErrBadParam); }676677if (!err) {678err = krb5int_ipc_stream_new (&request);679}680681if (!err) {682err = krb5int_ipc_stream_write_uint32 (request, in_lock_type);683}684685if (!err) {686err = krb5int_ipc_stream_write_uint32 (request, in_block);687}688689if (!err) {690err = cci_context_sync (context, 1);691}692693if (!err) {694err = cci_ipc_send (cci_context_lock_msg_id,695context->identifier,696request,697NULL);698}699700krb5int_ipc_stream_release (request);701702return cci_check_error (err);703}704705/* ------------------------------------------------------------------------ */706707cc_int32 ccapi_context_unlock (cc_context_t in_context)708{709cc_int32 err = ccNoError;710cci_context_t context = (cci_context_t) in_context;711712if (!in_context) { err = cci_check_error (ccErrBadParam); }713714if (!err) {715err = cci_context_sync (context, 1);716}717718if (!err) {719err = cci_ipc_send (cci_context_unlock_msg_id,720context->identifier,721NULL,722NULL);723}724725return cci_check_error (err);726}727728/* ------------------------------------------------------------------------ */729730cc_int32 ccapi_context_compare (cc_context_t in_context,731cc_context_t in_compare_to_context,732cc_uint32 *out_equal)733{734cc_int32 err = ccNoError;735cci_context_t context = (cci_context_t) in_context;736cci_context_t compare_to_context = (cci_context_t) in_compare_to_context;737738if (!in_context ) { err = cci_check_error (ccErrBadParam); }739if (!in_compare_to_context) { err = cci_check_error (ccErrBadParam); }740if (!out_equal ) { err = cci_check_error (ccErrBadParam); }741742if (!err) {743err = cci_context_sync (context, 0);744}745746if (!err) {747err = cci_context_sync (compare_to_context, 0);748}749750if (!err) {751/* If both contexts can't talk to the server, then752* we assume they are equivalent */753err = cci_identifier_compare (context->identifier,754compare_to_context->identifier,755out_equal);756}757758return cci_check_error (err);759}760761#ifdef TARGET_OS_MAC762#pragma mark -763#endif764765/* ------------------------------------------------------------------------ */766767static cc_int32 cci_context_sync (cci_context_t in_context,768cc_uint32 in_launch)769{770cc_int32 err = ccNoError;771cci_context_t context = (cci_context_t) in_context;772k5_ipc_stream reply = NULL;773cci_identifier_t new_identifier = NULL;774775if (!in_context) { err = cci_check_error (ccErrBadParam); }776777if (!err) {778/* Use the uninitialized identifier because we may be talking */779/* to a different server which would reject our identifier and */780/* the point of this message is to sync with the server's id */781if (in_launch) {782err = cci_ipc_send (cci_context_sync_msg_id,783cci_identifier_uninitialized,784NULL,785&reply);786} else {787err = cci_ipc_send_no_launch (cci_context_sync_msg_id,788cci_identifier_uninitialized,789NULL,790&reply);791}792}793794if (!err) {795if (krb5int_ipc_stream_size (reply) > 0) {796err = cci_identifier_read (&new_identifier, reply);797} else {798new_identifier = cci_identifier_uninitialized;799}800}801802if (!err) {803cc_uint32 equal = 0;804805err = cci_identifier_compare (context->identifier, new_identifier, &equal);806807if (!err && !equal) {808if (context->identifier) {809cci_identifier_release (context->identifier);810}811context->identifier = new_identifier;812new_identifier = NULL; /* take ownership */813}814}815816if (!err && context->synchronized) {817err = cci_context_change_time_sync (context->identifier);818}819820if (!err && !context->synchronized) {821/* Keep state about whether this is the first call to avoid always */822/* modifying the global change time on the context's first ipc call. */823context->synchronized = 1;824}825826cci_identifier_release (new_identifier);827krb5int_ipc_stream_release (reply);828829return cci_check_error (err);830}831832833