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
main(int argc,const char * argv[])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
ccs_server_new_identifier(cci_identifier_t * out_identifier)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
ccs_server_add_client(ccs_pipe_t in_connection_pipe)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
ccs_server_remove_client(ccs_pipe_t in_connection_pipe)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
ccs_server_client_for_pipe(ccs_pipe_t in_client_pipe,ccs_client_t * out_client)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
ccs_server_client_is_valid(ccs_pipe_t in_client_pipe,cc_uint32 * out_client_is_valid)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
ccs_server_request_demux(ccs_pipe_t in_client_pipe,ccs_pipe_t in_reply_pipe,ccs_cache_collection_t in_cache_collection,enum cci_msg_id_t in_request_name,cci_identifier_t in_request_identifier,k5_ipc_stream in_request_data,cc_uint32 * out_will_block,k5_ipc_stream * out_reply_data)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
ccs_server_handle_request(ccs_pipe_t in_client_pipe,ccs_pipe_t in_reply_pipe,k5_ipc_stream in_request)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
ccs_server_send_reply(ccs_pipe_t in_reply_pipe,cc_int32 in_reply_err,k5_ipc_stream in_reply_data)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
ccs_server_client_count(void)405 cc_uint64 ccs_server_client_count (void)
406 {
407 return ccs_client_array_count (g_client_array);
408 }
409