1 /* ccapi/server/ccs_server.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 "ccs_common.h" 27 #include "ccs_os_server.h" 28 29 /* Server Globals: */ 30 31 cci_uuid_string_t g_server_id = NULL; 32 ccs_cache_collection_t g_cache_collection = NULL; 33 ccs_client_array_t g_client_array = NULL; 34 35 /* ------------------------------------------------------------------------ */ 36 37 int main (int argc, const char *argv[]) 38 { 39 cc_int32 err = 0; 40 41 if (!err) { 42 err = ccs_os_server_initialize (argc, argv); 43 } 44 45 if (!err) { 46 err = cci_identifier_new_uuid (&g_server_id); 47 } 48 49 if (!err) { 50 err = ccs_cache_collection_new (&g_cache_collection); 51 } 52 53 if (!err) { 54 err = ccs_client_array_new (&g_client_array); 55 } 56 57 if (!err) { 58 err = ccs_os_server_listen_loop (argc, argv); 59 } 60 61 if (!err) { 62 free (g_server_id); 63 cci_check_error (ccs_cache_collection_release (g_cache_collection)); 64 cci_check_error (ccs_client_array_release (g_client_array)); 65 66 err = ccs_os_server_cleanup (argc, argv); 67 } 68 69 return cci_check_error (err) ? 1 : 0; 70 } 71 72 #ifdef TARGET_OS_MAC 73 #pragma mark - 74 #endif 75 76 /* ------------------------------------------------------------------------ */ 77 78 cc_int32 ccs_server_new_identifier (cci_identifier_t *out_identifier) 79 { 80 return cci_check_error (cci_identifier_new (out_identifier, 81 g_server_id)); 82 } 83 84 #ifdef TARGET_OS_MAC 85 #pragma mark - 86 #endif 87 88 /* ------------------------------------------------------------------------ */ 89 90 cc_int32 ccs_server_add_client (ccs_pipe_t in_connection_pipe) 91 { 92 cc_int32 err = ccNoError; 93 ccs_client_t client = NULL; 94 95 if (!err) { 96 err = ccs_client_new (&client, in_connection_pipe); 97 } 98 99 if (!err) { 100 cci_debug_printf ("%s: Adding client %p.", __FUNCTION__, client); 101 err = ccs_client_array_insert (g_client_array, 102 client, 103 ccs_client_array_count (g_client_array)); 104 } 105 106 return cci_check_error (err); 107 } 108 109 /* ------------------------------------------------------------------------ */ 110 111 cc_int32 ccs_server_remove_client (ccs_pipe_t in_connection_pipe) 112 { 113 cc_int32 err = ccNoError; 114 115 if (!err) { 116 cc_uint64 i; 117 cc_uint64 count = ccs_client_array_count (g_client_array); 118 cc_uint32 found = 0; 119 120 for (i = 0; !err && i < count; i++) { 121 ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i); 122 123 err = ccs_client_uses_pipe (client, in_connection_pipe, &found); 124 125 if (!err && found) { 126 cci_debug_printf ("%s: Removing client %p.", __FUNCTION__, client); 127 err = ccs_client_array_remove (g_client_array, i); 128 break; 129 } 130 } 131 132 if (!err && !found) { 133 cci_debug_printf ("WARNING %s() didn't find client in client list.", 134 __FUNCTION__); 135 } 136 } 137 138 return cci_check_error (err); 139 } 140 141 /* ------------------------------------------------------------------------ */ 142 143 cc_int32 ccs_server_client_for_pipe (ccs_pipe_t in_client_pipe, 144 ccs_client_t *out_client) 145 { 146 cc_int32 err = ccNoError; 147 ccs_client_t client_for_pipe = NULL; 148 149 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 150 if (!out_client ) { err = cci_check_error (ccErrBadParam); } 151 152 if (!err) { 153 cc_uint64 i; 154 cc_uint64 count = ccs_client_array_count (g_client_array); 155 156 for (i = 0; !err && i < count; i++) { 157 ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i); 158 cc_uint32 uses_pipe = 0; 159 160 err = ccs_client_uses_pipe (client, in_client_pipe, &uses_pipe); 161 162 if (!err && uses_pipe) { 163 client_for_pipe = client; 164 break; 165 } 166 } 167 } 168 169 if (!err) { 170 *out_client = client_for_pipe; /* may be NULL if not found */ 171 } 172 173 return cci_check_error (err); 174 } 175 176 /* ------------------------------------------------------------------------ */ 177 178 cc_int32 ccs_server_client_is_valid (ccs_pipe_t in_client_pipe, 179 cc_uint32 *out_client_is_valid) 180 { 181 cc_int32 err = ccNoError; 182 ccs_client_t client = NULL; 183 184 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 185 if (!out_client_is_valid ) { err = cci_check_error (ccErrBadParam); } 186 187 if (!err) { 188 err = ccs_server_client_for_pipe (in_client_pipe, &client); 189 } 190 191 if (!err) { 192 *out_client_is_valid = (client != NULL); 193 } 194 195 return cci_check_error (err); 196 } 197 198 #ifdef TARGET_OS_MAC 199 #pragma mark - 200 #endif 201 202 /* ------------------------------------------------------------------------ */ 203 204 static cc_int32 ccs_server_request_demux (ccs_pipe_t in_client_pipe, 205 ccs_pipe_t in_reply_pipe, 206 ccs_cache_collection_t in_cache_collection, 207 enum cci_msg_id_t in_request_name, 208 cci_identifier_t in_request_identifier, 209 k5_ipc_stream in_request_data, 210 cc_uint32 *out_will_block, 211 k5_ipc_stream *out_reply_data) 212 { 213 cc_int32 err = ccNoError; 214 215 if (!ccs_pipe_valid (in_reply_pipe)) { err = cci_check_error (ccErrBadParam); } 216 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 217 if (!out_will_block ) { err = cci_check_error (ccErrBadParam); } 218 if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); } 219 220 if (!err) { 221 if (in_request_name > cci_context_first_msg_id && 222 in_request_name < cci_context_last_msg_id) { 223 /* Note: context identifier doesn't need to match. 224 * Client just uses the identifier to detect server relaunch. */ 225 226 if (!err) { 227 err = ccs_cache_collection_handle_message (in_client_pipe, 228 in_reply_pipe, 229 in_cache_collection, 230 in_request_name, 231 in_request_data, 232 out_will_block, 233 out_reply_data); 234 } 235 236 } else if (in_request_name > cci_ccache_first_msg_id && 237 in_request_name < cci_ccache_last_msg_id) { 238 ccs_ccache_t ccache = NULL; 239 240 err = ccs_cache_collection_find_ccache (in_cache_collection, 241 in_request_identifier, 242 &ccache); 243 244 if (!err) { 245 err = ccs_ccache_handle_message (in_client_pipe, 246 in_reply_pipe, 247 ccache, 248 in_cache_collection, 249 in_request_name, 250 in_request_data, 251 out_will_block, 252 out_reply_data); 253 } 254 255 } else if (in_request_name > cci_ccache_iterator_first_msg_id && 256 in_request_name < cci_ccache_iterator_last_msg_id) { 257 ccs_ccache_iterator_t ccache_iterator = NULL; 258 259 err = ccs_cache_collection_find_ccache_iterator (in_cache_collection, 260 in_request_identifier, 261 &ccache_iterator); 262 263 if (!err) { 264 err = ccs_ccache_iterator_handle_message (ccache_iterator, 265 in_cache_collection, 266 in_request_name, 267 in_request_data, 268 out_reply_data); 269 } 270 271 if (!err) { 272 *out_will_block = 0; /* can't block */ 273 } 274 275 } else if (in_request_name > cci_credentials_iterator_first_msg_id && 276 in_request_name < cci_credentials_iterator_last_msg_id) { 277 ccs_credentials_iterator_t credentials_iterator = NULL; 278 ccs_ccache_t ccache = NULL; 279 280 err = ccs_cache_collection_find_credentials_iterator (in_cache_collection, 281 in_request_identifier, 282 &ccache, 283 &credentials_iterator); 284 285 if (!err) { 286 err = ccs_credentials_iterator_handle_message (credentials_iterator, 287 ccache, 288 in_request_name, 289 in_request_data, 290 out_reply_data); 291 } 292 293 if (!err) { 294 *out_will_block = 0; /* can't block */ 295 } 296 297 } else { 298 err = ccErrBadInternalMessage; 299 } 300 } 301 302 return cci_check_error (err); 303 } 304 305 #ifdef TARGET_OS_MAC 306 #pragma mark - 307 #endif 308 309 /* ------------------------------------------------------------------------ */ 310 311 cc_int32 ccs_server_handle_request (ccs_pipe_t in_client_pipe, 312 ccs_pipe_t in_reply_pipe, 313 k5_ipc_stream in_request) 314 { 315 cc_int32 err = ccNoError; 316 enum cci_msg_id_t request_name = 0; 317 cci_identifier_t request_identifier = NULL; 318 cc_uint32 will_block = 0; 319 k5_ipc_stream reply_data = NULL; 320 321 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 322 if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); } 323 if (!in_request ) { err = cci_check_error (ccErrBadParam); } 324 325 if (!err) { 326 err = cci_message_read_request_header (in_request, 327 &request_name, 328 &request_identifier); 329 } 330 331 if (!err) { 332 cc_uint32 server_err = 0; 333 cc_uint32 valid = 0; 334 ccs_cache_collection_t cache_collection = g_cache_collection; 335 336 server_err = cci_identifier_is_for_server (request_identifier, 337 g_server_id, 338 &valid); 339 340 if (!server_err && !valid) { 341 server_err = cci_message_invalid_object_err (request_name); 342 } 343 344 if (!server_err) { 345 346 /* Monolithic server implementation would need to select 347 * cache collection here. Currently we only support per-user 348 * servers so we always use the same cache collection. */ 349 350 server_err = ccs_server_request_demux (in_client_pipe, 351 in_reply_pipe, 352 cache_collection, 353 request_name, 354 request_identifier, 355 in_request, 356 &will_block, 357 &reply_data); 358 } 359 360 if (server_err || !will_block) { 361 362 /* send a reply now if the server isn't blocked on something */ 363 err = ccs_server_send_reply (in_reply_pipe, server_err, reply_data); 364 } 365 } 366 367 cci_identifier_release (request_identifier); 368 krb5int_ipc_stream_release (reply_data); 369 370 return cci_check_error (err); 371 } 372 373 /* ------------------------------------------------------------------------ */ 374 375 cc_int32 ccs_server_send_reply (ccs_pipe_t in_reply_pipe, 376 cc_int32 in_reply_err, 377 k5_ipc_stream in_reply_data) 378 { 379 cc_int32 err = ccNoError; 380 k5_ipc_stream reply = NULL; 381 382 if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); } 383 384 if (!err) { 385 err = cci_message_new_reply_header (&reply, in_reply_err); 386 } 387 388 if (!err && in_reply_data && krb5int_ipc_stream_size (in_reply_data) > 0) { 389 err = krb5int_ipc_stream_write (reply, 390 krb5int_ipc_stream_data (in_reply_data), 391 krb5int_ipc_stream_size (in_reply_data)); 392 } 393 394 if (!err) { 395 err = ccs_os_server_send_reply (in_reply_pipe, reply); 396 } 397 398 krb5int_ipc_stream_release (reply); 399 400 return cci_check_error (err); 401 } 402 403 /* ------------------------------------------------------------------------ */ 404 405 cc_uint64 ccs_server_client_count () 406 { 407 return ccs_client_array_count (g_client_array); 408 } 409