cc_int32 ccs_callback_reply_to_client (ccs_callback_t io_callback, k5_ipc_stream in_stream) { cc_int32 err = ccNoError; if (!io_callback) { err = cci_check_error (ccErrBadParam); } if (!err) { if (io_callback->pending) { cci_debug_printf ("%s: callback %p replying to client.", __FUNCTION__, io_callback); err = ccs_server_send_reply (io_callback->reply_pipe, err, in_stream); if (err) { cci_debug_printf ("WARNING %s() called on a lock belonging to a dead client!", __FUNCTION__); } io_callback->pending = 0; } else { cci_debug_printf ("WARNING %s() called on non-pending callback!", __FUNCTION__); } } return cci_check_error (err); }
static cc_int32 ccs_ccache_wait_for_change (ccs_pipe_t in_client_pipe, ccs_pipe_t in_reply_pipe, ccs_ccache_t io_ccache, ccs_cache_collection_t io_cache_collection, k5_ipc_stream in_request_data, k5_ipc_stream io_reply_data, cc_uint32 *out_will_block) { cc_int32 err = ccNoError; cc_time_t last_wait_for_change_time = 0; cc_uint32 will_block = 0; if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } if (!ccs_pipe_valid (in_reply_pipe )) { err = cci_check_error (ccErrBadParam); } if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); } if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } if (!out_will_block ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = krb5int_ipc_stream_read_time (in_request_data, &last_wait_for_change_time); } if (!err) { if (last_wait_for_change_time < io_ccache->last_changed_time) { cci_debug_printf ("%s returning immediately", __FUNCTION__); err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_changed_time); } else { ccs_callback_t callback = NULL; err = ccs_callback_new (&callback, ccErrInvalidCCache, in_client_pipe, in_reply_pipe, (ccs_callback_owner_t) io_ccache, ccs_ccache_invalidate_change_callback); if (!err) { err = ccs_callback_array_insert (io_ccache->change_callbacks, callback, ccs_callback_array_count (io_ccache->change_callbacks)); if (!err) { callback = NULL; /* take ownership */ } cci_debug_printf ("%s blocking", __FUNCTION__); will_block = 1; } ccs_callback_release (callback); } } if (!err) { *out_will_block = will_block; } return cci_check_error (err); }
WorkList::~WorkList() { // Delete any WorkItems in the queue: WorkItem* item; cci_debug_printf("%s", __FUNCTION__); char buf[2048]; char* pbuf = (char*)buf; while (remove(&item)) { cci_debug_printf("WorkList::~WorkList() deleting %s", item->print(pbuf)); delete item; } DeleteCriticalSection(&cs); }
cc_int32 ccs_lock_state_remove (ccs_lock_state_t io_lock_state, ccs_pipe_t in_client_pipe) { cc_int32 err = ccNoError; cc_uint32 found_lock = 0; if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); } if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } if (!err) { cc_uint64 i; /* Remove all locks for this client. * There should only be one so warn if there are multiple */ for (i = 0; !err && i < io_lock_state->first_pending_lock_index; i++) { ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i); cc_uint32 is_for_client = 0; err = ccs_lock_is_for_client_pipe (lock, in_client_pipe, &is_for_client); if (!err && is_for_client) { if (found_lock) { cci_debug_printf ("WARNING %s: Found multiple locks for client.", __FUNCTION__); } found_lock = 1; cci_debug_printf ("%s: Removing lock %p at index %d.", __FUNCTION__, lock, (int) i); err = ccs_lock_status_remove_lock (io_lock_state, i); if (!err) { i--; /* We removed one so back up an index */ } } } } if (!err && !found_lock) { err = cci_check_error (io_lock_state->no_lock_err); } if (!err) { err = ccs_lock_status_try_to_grant_pending_locks (io_lock_state); } return cci_check_error (err); }
cci_array_object_t cci_array_object_at_index (cci_array_t io_array, cc_uint64 in_position) { if (io_array && in_position < io_array->count) { return io_array->objects[in_position]; } else { if (!io_array) { cci_debug_printf ("%s() got NULL array", __FUNCTION__); } else { cci_debug_printf ("%s() got bad index %lld (count = %lld)", __FUNCTION__, in_position, io_array->count); } return NULL; } }
cc_int32 ccapi_ccache_iterator_release (cc_ccache_iterator_t io_ccache_iterator) { cc_int32 err = ccNoError; cci_ccache_iterator_t ccache_iterator = (cci_ccache_iterator_t) io_ccache_iterator; if (!io_ccache_iterator) { err = ccErrBadParam; } if (!err) { cc_uint32 initialized = 0; err = cci_identifier_is_initialized (ccache_iterator->identifier, &initialized); if (!err && initialized) { err = cci_ipc_send (cci_ccache_iterator_release_msg_id, ccache_iterator->identifier, NULL, NULL); if (err) { cci_debug_printf ("%s: cci_ipc_send failed with error %d", __FUNCTION__, err); err = ccNoError; } } } if (!err) { free ((char *) ccache_iterator->functions); cci_identifier_release (ccache_iterator->identifier); free (ccache_iterator->saved_ccache_name); free (ccache_iterator); } return err; }
HANDLE createThreadEvent(char* uuid, char* suffix) { LPSTR event_name = NULL; HANDLE hEvent = NULL; PSECURITY_ATTRIBUTES psa = 0; // Everything having to do with SECURITY_ATTRIBUTES sa = { 0 }; // sa, psa, security is copied DWORD status = 0; // from the previous implementation. psa = isNT() ? &sa : 0; if (isNT()) { sa.nLength = sizeof(sa); status = alloc_own_security_descriptor_NT(&sa.lpSecurityDescriptor); cci_check_error(status); } if (!status) { event_name = allocEventName(uuid, suffix); if (!event_name) status = cci_check_error(ccErrNoMem); } #if 0 cci_debug_printf("%s event_name:%s", __FUNCTION__, event_name); #endif if (!status) { hEvent = CreateEvent(psa, FALSE, FALSE, event_name); if (!hEvent) status = cci_check_error(GetLastError()); } if (!status) ResetEvent(hEvent); if (event_name) free(event_name); if (isNT()) free(sa.lpSecurityDescriptor); return hEvent; }
BOOL isNT() { OSVERSIONINFO osvi; DWORD status = 0; BOOL bSupportedVersion = FALSE; BOOL bIsNT = FALSE; memset(&osvi, 0, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); status = !GetVersionEx(&osvi); // Returns a boolean. Invert to 0 is OK. if (!status) { switch(osvi.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: bIsNT = FALSE; bSupportedVersion = TRUE; break; case VER_PLATFORM_WIN32_NT: bIsNT = TRUE; bSupportedVersion = TRUE; break; case VER_PLATFORM_WIN32s: default: bIsNT = FALSE; break; } if (!bSupportedVersion) { cci_debug_printf("%s Running on an unsupported version of Windows", __FUNCTION__); status = 1; } } return (!status && bIsNT && bSupportedVersion); }
void ccs_rpc_request( const long rpcmsg, /* Message type */ const char tspHandle[], /* Client's tspdata* */ const char* pszUUID, /* Where client will listen for the reply */ const long lenRequest, /* Length of buffer */ const char pbRequest[], /* Data buffer */ const long serverStartTime, /* Which server session we're talking to */ long* return_status ) { /* Return code */ cc_int32 status = 0; k5_ipc_stream stream; DWORD* p = (DWORD*)(tspHandle); WIN_PIPE* pipe = NULL; #if 0 cci_debug_printf("%s rpcmsg:%d; UUID:<%s> SST:<%s>", __FUNCTION__, rpcmsg, pszUUID, serverStartTime); #endif status = (rpcmsg != CCMSG_REQUEST) && (rpcmsg != CCMSG_PING); if (!status) { status = k5_ipc_stream_new (&stream); /* Create a stream for the request data */ } if (!status) { /* Put the data into the stream */ status = k5_ipc_stream_write (stream, pbRequest, lenRequest); } pipe = ccs_win_pipe_new(pszUUID, *p); worklist_add(rpcmsg, pipe, stream, serverStartTime); *return_status = status; }
// 'Authentication' is client setting a value in a file and the server // returning that value plus one. CC_UINT32 ccs_authenticate(const CC_CHAR* name) { HANDLE hMap = 0; PDWORD pvalue = 0; CC_UINT32 result = 0; DWORD status = 0; #if 0 cci_debug_printf("%s ( %s )", __FUNCTION__, name); #endif hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, (LPSTR)name); status = !hMap; if (!status) { pvalue = (PDWORD)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); status = !pvalue; } if (!status) { *pvalue += 1; result = *pvalue; } if (pvalue) { UnmapViewOfFile(pvalue); } if (hMap) CloseHandle(hMap); return result; }
struct ccs_win_pipe_t* ccs_win_pipe_new (const char* uuid, const HANDLE h) { cc_int32 err = ccNoError; struct ccs_win_pipe_t* out_pipe = NULL; char* uuidCopy = NULL; if (!err) { if (!uuid) {err = cci_check_error(ccErrBadParam);} } if (!err) { uuidCopy = (char*)malloc(1+strlen(uuid)); if (!uuidCopy) {err = cci_check_error(ccErrBadParam);} strcpy(uuidCopy, uuid); } if (!err) { out_pipe = (struct ccs_win_pipe_t*)malloc(sizeof(struct ccs_win_pipe_t)); if (!out_pipe) {err = cci_check_error(ccErrBadParam);} out_pipe->uuid = uuidCopy; out_pipe->clientHandle = h; } #if 0 cci_debug_printf("0x%X = %s(%s, 0x%X)", out_pipe, __FUNCTION__, uuid, h); #endif return out_pipe; }
cc_int32 cci_context_change_time_update (cci_identifier_t in_identifier, cc_time_t in_new_change_time) { cc_int32 err = ccNoError; cc_int32 lock_err = err = k5_mutex_lock (&g_change_time_mutex); if (!err) { if (!in_identifier) { err = cci_check_error (err); } } if (!err) { if (g_change_time < in_new_change_time) { /* Only update if it increases the time. May be a different server. */ g_change_time = in_new_change_time; cci_debug_printf ("%s: setting change time to %d", __FUNCTION__, in_new_change_time); } } if (!err) { err = cci_context_change_time_update_identifier (in_identifier, NULL, NULL, NULL); } if (!lock_err) { k5_mutex_unlock (&g_change_time_mutex); } return err; }
static cc_int32 ccs_ccache_invalidate_change_callback (ccs_callback_owner_t io_ccache, ccs_callback_t in_callback) { cc_int32 err = ccNoError; if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!in_callback) { err = cci_check_error (ccErrBadParam); } if (!err) { /* Remove callback */ ccs_ccache_t ccache = (ccs_ccache_t) io_ccache; cc_uint64 i; cc_uint64 count = ccs_callback_array_count (ccache->change_callbacks); for (i = 0; !err && i < count; i++) { ccs_callback_t callback = ccs_callback_array_object_at_index (ccache->change_callbacks, i); if (callback == in_callback) { cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback); err = ccs_callback_array_remove (ccache->change_callbacks, i); break; } } } return cci_check_error (err); }
cc_int32 ccs_ccache_changed (ccs_ccache_t io_ccache, ccs_cache_collection_t io_cache_collection) { cc_int32 err = ccNoError; k5_ipc_stream reply_data = NULL; if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } if (!err) { cc_time_t now = time (NULL); if (io_ccache->last_changed_time < now) { io_ccache->last_changed_time = now; } else { io_ccache->last_changed_time++; } } if (!err) { err = ccs_cache_collection_changed (io_cache_collection); } if (!err) { err = krb5int_ipc_stream_new (&reply_data); } if (!err) { err = krb5int_ipc_stream_write_time (reply_data, io_ccache->last_changed_time); } if (!err) { /* Loop over callbacks sending messages to them */ cc_uint64 i; cc_uint64 count = ccs_callback_array_count (io_ccache->change_callbacks); for (i = 0; !err && i < count; i++) { ccs_callback_t callback = ccs_callback_array_object_at_index (io_ccache->change_callbacks, i); err = ccs_callback_reply_to_client (callback, reply_data); if (!err) { cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback); err = ccs_callback_array_remove (io_ccache->change_callbacks, i); break; } } } if (!err) { err = ccs_os_notify_ccache_changed (io_cache_collection, io_ccache->name); } krb5int_ipc_stream_release (reply_data); return cci_check_error (err); }
void ccs_rpc_connect( const long rpcmsg, /* Message type */ const char tspHandle[], /* Client's tspdata* */ const char* pszUUID, /* Data buffer */ long* return_status ) { /* Return code */ DWORD* p = (DWORD*)(tspHandle); WIN_PIPE* pipe = ccs_win_pipe_new(pszUUID, *p); #if 0 cci_debug_printf("%s; rpcmsg:%d; UUID: <%s>", __FUNCTION__, rpcmsg, pszUUID); #endif worklist_add( rpcmsg, pipe, NULL, /* No payload with connect request */ (const time_t)0 ); /* No server session number with connect request */ }
cc_int32 cci_context_change_time_sync (cci_identifier_t in_new_identifier) { cc_int32 err = ccNoError; cc_int32 lock_err = err = k5_mutex_lock (&g_change_time_mutex); cc_uint32 server_ids_match = 0; cc_uint32 server_was_running = 0; cc_uint32 server_is_running = 0; if (!err) { if (!in_new_identifier) { err = cci_check_error (err); } } if (!err) { err = cci_context_change_time_update_identifier (in_new_identifier, &server_ids_match, &server_was_running, &server_is_running); } if (!err && !server_ids_match) { /* Increment the change time so callers re-read */ g_change_time_offset++; /* If the server died, absorb the offset */ if (server_was_running && !server_is_running) { cc_time_t now = time (NULL); g_change_time += g_change_time_offset; g_change_time_offset = 0; /* Make sure the change time increases, ideally with the current time */ g_change_time = (g_change_time < now) ? now : g_change_time; } cci_debug_printf ("%s noticed server changed (" "server_was_running = %d; server_is_running = %d; " "g_change_time = %d; g_change_time_offset = %d", __FUNCTION__, server_was_running, server_is_running, g_change_time, g_change_time_offset); } if (!lock_err) { k5_mutex_unlock (&g_change_time_mutex); } return err; }
cc_int32 ccs_callback_invalidate (ccs_callback_t io_callback) { cc_int32 err = ccNoError; if (!io_callback) { err = cci_check_error (ccErrBadParam); } if (!err) { io_callback->pending = 0; /* client is dead, don't try to talk to it */ if (io_callback->owner_invalidate) { err = io_callback->owner_invalidate (io_callback->owner, io_callback); } else { cci_debug_printf ("WARNING %s() unable to notify callback owner!", __FUNCTION__); } } return cci_check_error (err); }
HANDLE openThreadEvent(char* uuid, char* suffix) { LPSTR event_name = NULL; HANDLE hEvent = NULL; DWORD status = 0; event_name = allocEventName(uuid, suffix); if (!event_name) status = cci_check_error(ccErrNoMem); #if 0 cci_debug_printf("%s event_name:%s", __FUNCTION__, event_name); #endif if (!status) { hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name); if (!hEvent) status = cci_check_error(GetLastError()); } if (event_name) free(event_name); return hEvent; }
cc_int32 ccs_list_iterator_release (ccs_list_iterator_t io_list_iterator) { cc_int32 err = ccNoError; if (!err && io_list_iterator) { cc_uint64 i = 0; if (ccs_list_find_iterator_index (io_list_iterator->list, io_list_iterator->identifier, &i) == ccNoError) { /* cci_array_remove will call ccs_list_iterator_object_release */ err = cci_array_remove (io_list_iterator->list->iterators, i); } else { cci_debug_printf ("Warning: iterator not in iterator list!"); } } return err; }
cc_int32 ccs_lock_state_add (ccs_lock_state_t io_lock_state, ccs_pipe_t in_client_pipe, ccs_pipe_t in_reply_pipe, cc_uint32 in_lock_type, cc_uint32 in_block, cc_uint32 *out_will_send_reply) { cc_int32 err = ccNoError; cc_uint32 can_grant_lock_now = 0; if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); } if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); } if (!out_will_send_reply ) { err = cci_check_error (ccErrBadParam); } if (!err) { /* Sanity check: if there are any pending locks for this client * the client must have timed out waiting for our reply. Remove any * existing pending locks for the client. */ cc_uint64 i; for (i = io_lock_state->first_pending_lock_index; !err && i < ccs_lock_array_count (io_lock_state->locks); i++) { ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i); cc_uint32 has_pending_lock_for_client = 0; err = ccs_lock_is_for_client_pipe (lock, in_client_pipe, &has_pending_lock_for_client); if (!err && has_pending_lock_for_client) { cci_debug_printf ("WARNING %s: Removing unexpected pending lock %p at index %d.", __FUNCTION__, lock, (int) i); err = ccs_lock_status_remove_lock (io_lock_state, i); if (!err) { i--; /* We removed one so back up an index */ } } } } if (!err) { err = ccs_lock_state_check_pending_lock (io_lock_state, in_client_pipe, in_lock_type, &can_grant_lock_now); } if (!err) { if (!can_grant_lock_now && (in_block == cc_lock_noblock)) { err = cci_check_error (io_lock_state->pending_lock_err); } else { cc_uint64 new_lock_index = 0; err = ccs_lock_status_add_pending_lock (io_lock_state, in_client_pipe, in_reply_pipe, in_lock_type, &new_lock_index); if (!err && can_grant_lock_now) { err = ccs_lock_status_grant_lock (io_lock_state, new_lock_index); if (!err && (in_lock_type == cc_lock_downgrade)) { /* downgrades can allow us to grant other locks */ err = ccs_lock_status_try_to_grant_pending_locks (io_lock_state); } } } } if (!err) { /* ccs_lock_state_add sends its replies via callback so caller shouldn't */ *out_will_send_reply = 1; } return cci_check_error (err); }
static cc_int32 ccs_lock_status_grant_lock (ccs_lock_state_t io_lock_state, cc_uint64 in_pending_lock_index) { cc_int32 err = ccNoError; ccs_lock_t pending_lock = NULL; cc_uint32 type = 0; if (!io_lock_state) { err = cci_check_error (ccErrBadParam); } if (!err) { pending_lock = ccs_lock_array_object_at_index (io_lock_state->locks, in_pending_lock_index); if (!pending_lock || in_pending_lock_index < io_lock_state->first_pending_lock_index) { err = cci_check_error (ccErrBadParam); } } if (!err) { err = ccs_lock_type (pending_lock, &type); } if (!err && (type == cc_lock_upgrade || type == cc_lock_downgrade)) { /* lock upgrades or downgrades. Find the old lock and remove it. */ ccs_pipe_t pending_client_pipe = CCS_PIPE_NULL; err = ccs_lock_client_pipe (pending_lock, &pending_client_pipe); if (!err) { cc_uint64 i; for (i = 0; !err && i < io_lock_state->first_pending_lock_index; i++) { ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i); cc_uint32 is_lock_for_client = 0; err = ccs_lock_is_for_client_pipe (lock, pending_client_pipe, &is_lock_for_client); if (!err && is_lock_for_client) { cci_debug_printf ("%s: Removing old lock %p at index %d to replace with pending lock %p.", __FUNCTION__, lock, (int) i, pending_lock); err = ccs_lock_status_remove_lock (io_lock_state, i); if (!err) { i--; in_pending_lock_index--; /* We removed one so back up an index */ } break; } } } } if (!err) { cc_uint64 new_lock_index = 0; err = ccs_lock_array_move (io_lock_state->locks, in_pending_lock_index, io_lock_state->first_pending_lock_index, &new_lock_index); if (!err) { io_lock_state->first_pending_lock_index++; } } if (!err) { err = ccs_lock_grant_lock (pending_lock); } return cci_check_error (err); }
cc_int32 ccs_ccache_new (ccs_ccache_t *out_ccache, cc_uint32 in_creds_version, const char *in_name, const char *in_principal, ccs_ccache_list_t io_ccache_list) { cc_int32 err = ccNoError; ccs_ccache_t ccache = NULL; if (!out_ccache ) { err = cci_check_error (ccErrBadParam); } if (!in_name ) { err = cci_check_error (ccErrBadParam); } if (!in_principal) { err = cci_check_error (ccErrBadParam); } if (!err) { ccache = malloc (sizeof (*ccache)); if (ccache) { *ccache = ccs_ccache_initializer; } else { err = cci_check_error (ccErrNoMem); } } if (!err) { err = ccs_server_new_identifier (&ccache->identifier); } if (!err) { err = ccs_lock_state_new (&ccache->lock_state, ccErrInvalidCCache, ccErrCCacheLocked, ccErrCCacheUnlocked); } if (!err) { ccache->name = strdup (in_name); if (!ccache->name) { err = cci_check_error (ccErrNoMem); } } if (!err) { ccache->creds_version = in_creds_version; if (ccache->creds_version == cc_credentials_v5) { ccache->v5_principal = strdup (in_principal); if (!ccache->v5_principal) { err = cci_check_error (ccErrNoMem); } } else { err = cci_check_error (ccErrBadCredentialsVersion); } } if (!err) { err = ccs_credentials_list_new (&ccache->credentials); } if (!err) { err = ccs_callback_array_new (&ccache->change_callbacks); } if (!err) { cc_uint64 now = time (NULL); cc_uint64 count = 0; err = ccs_ccache_list_count (io_ccache_list, &count); if (!err) { /* first cache is default */ ccache->last_default_time = (count == 0) ? now : 0; cci_debug_printf ("%s ccache->last_default_time is %d.", __FUNCTION__, ccache->last_default_time); ccache->last_changed_time = now; } } if (!err) { /* Add self to the list of ccaches */ err = ccs_ccache_list_add (io_ccache_list, ccache); } if (!err) { *out_ccache = ccache; ccache = NULL; } ccs_ccache_release (ccache); return cci_check_error (err); }