1 | /*
|
---|
2 | * Copyright (c) 2009 Kungliga Tekniska Högskolan
|
---|
3 | * (Royal Institute of Technology, Stockholm, Sweden).
|
---|
4 | * All rights reserved.
|
---|
5 | *
|
---|
6 | * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
---|
7 | *
|
---|
8 | * Redistribution and use in source and binary forms, with or without
|
---|
9 | * modification, are permitted provided that the following conditions
|
---|
10 | * are met:
|
---|
11 | *
|
---|
12 | * 1. Redistributions of source code must retain the above copyright
|
---|
13 | * notice, this list of conditions and the following disclaimer.
|
---|
14 | *
|
---|
15 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
16 | * notice, this list of conditions and the following disclaimer in the
|
---|
17 | * documentation and/or other materials provided with the distribution.
|
---|
18 | *
|
---|
19 | * 3. Neither the name of the Institute nor the names of its contributors
|
---|
20 | * may be used to endorse or promote products derived from this software
|
---|
21 | * without specific prior written permission.
|
---|
22 | *
|
---|
23 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
---|
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
---|
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
33 | * SUCH DAMAGE.
|
---|
34 | */
|
---|
35 |
|
---|
36 | #include "hi_locl.h"
|
---|
37 | #include <assert.h>
|
---|
38 |
|
---|
39 | #define MAX_PACKET_SIZE (128 * 1024)
|
---|
40 |
|
---|
41 | struct heim_sipc {
|
---|
42 | int (*release)(heim_sipc ctx);
|
---|
43 | heim_ipc_callback callback;
|
---|
44 | void *userctx;
|
---|
45 | void *mech;
|
---|
46 | };
|
---|
47 |
|
---|
48 | #if defined(__APPLE__) && defined(HAVE_GCD)
|
---|
49 |
|
---|
50 | #include "heim_ipcServer.h"
|
---|
51 | #include "heim_ipc_reply.h"
|
---|
52 | #include "heim_ipc_async.h"
|
---|
53 |
|
---|
54 | static dispatch_source_t timer;
|
---|
55 | static dispatch_queue_t timerq;
|
---|
56 | static uint64_t timeoutvalue;
|
---|
57 |
|
---|
58 | static dispatch_queue_t eventq;
|
---|
59 |
|
---|
60 | static dispatch_queue_t workq;
|
---|
61 |
|
---|
62 | static void
|
---|
63 | default_timer_ev(void)
|
---|
64 | {
|
---|
65 | exit(0);
|
---|
66 | }
|
---|
67 |
|
---|
68 | static void (*timer_ev)(void) = default_timer_ev;
|
---|
69 |
|
---|
70 | static void
|
---|
71 | set_timer(void)
|
---|
72 | {
|
---|
73 | dispatch_source_set_timer(timer,
|
---|
74 | dispatch_time(DISPATCH_TIME_NOW,
|
---|
75 | timeoutvalue * NSEC_PER_SEC),
|
---|
76 | timeoutvalue * NSEC_PER_SEC, 1000000);
|
---|
77 | }
|
---|
78 |
|
---|
79 | static void
|
---|
80 | init_globals(void)
|
---|
81 | {
|
---|
82 | static dispatch_once_t once;
|
---|
83 | dispatch_once(&once, ^{
|
---|
84 | timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL);
|
---|
85 | timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq);
|
---|
86 | dispatch_source_set_event_handler(timer, ^{ timer_ev(); } );
|
---|
87 |
|
---|
88 | workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
---|
89 | eventq = dispatch_queue_create("heim-ipc.event-queue", NULL);
|
---|
90 | });
|
---|
91 | }
|
---|
92 |
|
---|
93 | static void
|
---|
94 | suspend_timer(void)
|
---|
95 | {
|
---|
96 | dispatch_suspend(timer);
|
---|
97 | }
|
---|
98 |
|
---|
99 | static void
|
---|
100 | restart_timer(void)
|
---|
101 | {
|
---|
102 | dispatch_sync(timerq, ^{ set_timer(); });
|
---|
103 | dispatch_resume(timer);
|
---|
104 | }
|
---|
105 |
|
---|
106 | struct mach_service {
|
---|
107 | mach_port_t sport;
|
---|
108 | dispatch_source_t source;
|
---|
109 | dispatch_queue_t queue;
|
---|
110 | };
|
---|
111 |
|
---|
112 | struct mach_call_ctx {
|
---|
113 | mach_port_t reply_port;
|
---|
114 | heim_icred cred;
|
---|
115 | heim_idata req;
|
---|
116 | };
|
---|
117 |
|
---|
118 |
|
---|
119 | static void
|
---|
120 | mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
---|
121 | {
|
---|
122 | struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
|
---|
123 | heim_ipc_message_inband_t replyin;
|
---|
124 | mach_msg_type_number_t replyinCnt;
|
---|
125 | heim_ipc_message_outband_t replyout;
|
---|
126 | mach_msg_type_number_t replyoutCnt;
|
---|
127 | kern_return_t kr;
|
---|
128 |
|
---|
129 | if (returnvalue) {
|
---|
130 | /* on error, no reply */
|
---|
131 | replyinCnt = 0;
|
---|
132 | replyout = 0; replyoutCnt = 0;
|
---|
133 | kr = KERN_SUCCESS;
|
---|
134 | } else if (reply->length < 2048) {
|
---|
135 | replyinCnt = reply->length;
|
---|
136 | memcpy(replyin, reply->data, replyinCnt);
|
---|
137 | replyout = 0; replyoutCnt = 0;
|
---|
138 | kr = KERN_SUCCESS;
|
---|
139 | } else {
|
---|
140 | replyinCnt = 0;
|
---|
141 | kr = vm_read(mach_task_self(),
|
---|
142 | (vm_address_t)reply->data, reply->length,
|
---|
143 | (vm_address_t *)&replyout, &replyoutCnt);
|
---|
144 | }
|
---|
145 |
|
---|
146 | mheim_ripc_call_reply(s->reply_port, returnvalue,
|
---|
147 | replyin, replyinCnt,
|
---|
148 | replyout, replyoutCnt);
|
---|
149 |
|
---|
150 | heim_ipc_free_cred(s->cred);
|
---|
151 | free(s->req.data);
|
---|
152 | free(s);
|
---|
153 | restart_timer();
|
---|
154 | }
|
---|
155 |
|
---|
156 | static void
|
---|
157 | mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
---|
158 | {
|
---|
159 | struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
|
---|
160 | heim_ipc_message_inband_t replyin;
|
---|
161 | mach_msg_type_number_t replyinCnt;
|
---|
162 | heim_ipc_message_outband_t replyout;
|
---|
163 | mach_msg_type_number_t replyoutCnt;
|
---|
164 | kern_return_t kr;
|
---|
165 |
|
---|
166 | if (returnvalue) {
|
---|
167 | /* on error, no reply */
|
---|
168 | replyinCnt = 0;
|
---|
169 | replyout = 0; replyoutCnt = 0;
|
---|
170 | kr = KERN_SUCCESS;
|
---|
171 | } else if (reply->length < 2048) {
|
---|
172 | replyinCnt = reply->length;
|
---|
173 | memcpy(replyin, reply->data, replyinCnt);
|
---|
174 | replyout = 0; replyoutCnt = 0;
|
---|
175 | kr = KERN_SUCCESS;
|
---|
176 | } else {
|
---|
177 | replyinCnt = 0;
|
---|
178 | kr = vm_read(mach_task_self(),
|
---|
179 | (vm_address_t)reply->data, reply->length,
|
---|
180 | (vm_address_t *)&replyout, &replyoutCnt);
|
---|
181 | }
|
---|
182 |
|
---|
183 | kr = mheim_aipc_acall_reply(s->reply_port, returnvalue,
|
---|
184 | replyin, replyinCnt,
|
---|
185 | replyout, replyoutCnt);
|
---|
186 | heim_ipc_free_cred(s->cred);
|
---|
187 | free(s->req.data);
|
---|
188 | free(s);
|
---|
189 | restart_timer();
|
---|
190 | }
|
---|
191 |
|
---|
192 |
|
---|
193 | kern_return_t
|
---|
194 | mheim_do_call(mach_port_t server_port,
|
---|
195 | audit_token_t client_creds,
|
---|
196 | mach_port_t reply_port,
|
---|
197 | heim_ipc_message_inband_t requestin,
|
---|
198 | mach_msg_type_number_t requestinCnt,
|
---|
199 | heim_ipc_message_outband_t requestout,
|
---|
200 | mach_msg_type_number_t requestoutCnt,
|
---|
201 | int *returnvalue,
|
---|
202 | heim_ipc_message_inband_t replyin,
|
---|
203 | mach_msg_type_number_t *replyinCnt,
|
---|
204 | heim_ipc_message_outband_t *replyout,
|
---|
205 | mach_msg_type_number_t *replyoutCnt)
|
---|
206 | {
|
---|
207 | heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
|
---|
208 | struct mach_call_ctx *s;
|
---|
209 | kern_return_t kr;
|
---|
210 | uid_t uid;
|
---|
211 | gid_t gid;
|
---|
212 | pid_t pid;
|
---|
213 | au_asid_t session;
|
---|
214 |
|
---|
215 | *replyout = NULL;
|
---|
216 | *replyoutCnt = 0;
|
---|
217 | *replyinCnt = 0;
|
---|
218 |
|
---|
219 | s = malloc(sizeof(*s));
|
---|
220 | if (s == NULL)
|
---|
221 | return KERN_MEMORY_FAILURE; /* XXX */
|
---|
222 |
|
---|
223 | s->reply_port = reply_port;
|
---|
224 |
|
---|
225 | audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
|
---|
226 |
|
---|
227 | kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
|
---|
228 | if (kr) {
|
---|
229 | free(s);
|
---|
230 | return kr;
|
---|
231 | }
|
---|
232 |
|
---|
233 | suspend_timer();
|
---|
234 |
|
---|
235 | if (requestinCnt) {
|
---|
236 | s->req.data = malloc(requestinCnt);
|
---|
237 | memcpy(s->req.data, requestin, requestinCnt);
|
---|
238 | s->req.length = requestinCnt;
|
---|
239 | } else {
|
---|
240 | s->req.data = malloc(requestoutCnt);
|
---|
241 | memcpy(s->req.data, requestout, requestoutCnt);
|
---|
242 | s->req.length = requestoutCnt;
|
---|
243 | }
|
---|
244 |
|
---|
245 | dispatch_async(workq, ^{
|
---|
246 | (ctx->callback)(ctx->userctx, &s->req, s->cred,
|
---|
247 | mach_complete_sync, (heim_sipc_call)s);
|
---|
248 | });
|
---|
249 |
|
---|
250 | return MIG_NO_REPLY;
|
---|
251 | }
|
---|
252 |
|
---|
253 | kern_return_t
|
---|
254 | mheim_do_call_request(mach_port_t server_port,
|
---|
255 | audit_token_t client_creds,
|
---|
256 | mach_port_t reply_port,
|
---|
257 | heim_ipc_message_inband_t requestin,
|
---|
258 | mach_msg_type_number_t requestinCnt,
|
---|
259 | heim_ipc_message_outband_t requestout,
|
---|
260 | mach_msg_type_number_t requestoutCnt)
|
---|
261 | {
|
---|
262 | heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
|
---|
263 | struct mach_call_ctx *s;
|
---|
264 | kern_return_t kr;
|
---|
265 | uid_t uid;
|
---|
266 | gid_t gid;
|
---|
267 | pid_t pid;
|
---|
268 | au_asid_t session;
|
---|
269 |
|
---|
270 | s = malloc(sizeof(*s));
|
---|
271 | if (s == NULL)
|
---|
272 | return KERN_MEMORY_FAILURE; /* XXX */
|
---|
273 |
|
---|
274 | s->reply_port = reply_port;
|
---|
275 |
|
---|
276 | audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
|
---|
277 |
|
---|
278 | kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
|
---|
279 | if (kr) {
|
---|
280 | free(s);
|
---|
281 | return kr;
|
---|
282 | }
|
---|
283 |
|
---|
284 | suspend_timer();
|
---|
285 |
|
---|
286 | if (requestinCnt) {
|
---|
287 | s->req.data = malloc(requestinCnt);
|
---|
288 | memcpy(s->req.data, requestin, requestinCnt);
|
---|
289 | s->req.length = requestinCnt;
|
---|
290 | } else {
|
---|
291 | s->req.data = malloc(requestoutCnt);
|
---|
292 | memcpy(s->req.data, requestout, requestoutCnt);
|
---|
293 | s->req.length = requestoutCnt;
|
---|
294 | }
|
---|
295 |
|
---|
296 | dispatch_async(workq, ^{
|
---|
297 | (ctx->callback)(ctx->userctx, &s->req, s->cred,
|
---|
298 | mach_complete_async, (heim_sipc_call)s);
|
---|
299 | });
|
---|
300 |
|
---|
301 | return KERN_SUCCESS;
|
---|
302 | }
|
---|
303 |
|
---|
304 | static int
|
---|
305 | mach_init(const char *service, mach_port_t sport, heim_sipc ctx)
|
---|
306 | {
|
---|
307 | struct mach_service *s;
|
---|
308 | char *name;
|
---|
309 |
|
---|
310 | init_globals();
|
---|
311 |
|
---|
312 | s = calloc(1, sizeof(*s));
|
---|
313 | if (s == NULL)
|
---|
314 | return ENOMEM;
|
---|
315 |
|
---|
316 | asprintf(&name, "heim-ipc-mach-%s", service);
|
---|
317 |
|
---|
318 | s->queue = dispatch_queue_create(name, NULL);
|
---|
319 | free(name);
|
---|
320 | s->sport = sport;
|
---|
321 |
|
---|
322 | s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
|
---|
323 | s->sport, 0, s->queue);
|
---|
324 | if (s->source == NULL) {
|
---|
325 | dispatch_release(s->queue);
|
---|
326 | free(s);
|
---|
327 | return ENOMEM;
|
---|
328 | }
|
---|
329 | ctx->mech = s;
|
---|
330 |
|
---|
331 | dispatch_set_context(s->queue, ctx);
|
---|
332 | dispatch_set_context(s->source, s);
|
---|
333 |
|
---|
334 | dispatch_source_set_event_handler(s->source, ^{
|
---|
335 | dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server);
|
---|
336 | });
|
---|
337 |
|
---|
338 | dispatch_source_set_cancel_handler(s->source, ^{
|
---|
339 | heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
|
---|
340 | struct mach_service *st = ctx->mech;
|
---|
341 | mach_port_mod_refs(mach_task_self(), st->sport,
|
---|
342 | MACH_PORT_RIGHT_RECEIVE, -1);
|
---|
343 | dispatch_release(st->queue);
|
---|
344 | dispatch_release(st->source);
|
---|
345 | free(st);
|
---|
346 | free(ctx);
|
---|
347 | });
|
---|
348 |
|
---|
349 | dispatch_resume(s->source);
|
---|
350 |
|
---|
351 | return 0;
|
---|
352 | }
|
---|
353 |
|
---|
354 | static int
|
---|
355 | mach_release(heim_sipc ctx)
|
---|
356 | {
|
---|
357 | struct mach_service *s = ctx->mech;
|
---|
358 | dispatch_source_cancel(s->source);
|
---|
359 | dispatch_release(s->source);
|
---|
360 | return 0;
|
---|
361 | }
|
---|
362 |
|
---|
363 | static mach_port_t
|
---|
364 | mach_checkin_or_register(const char *service)
|
---|
365 | {
|
---|
366 | mach_port_t mp;
|
---|
367 | kern_return_t kr;
|
---|
368 |
|
---|
369 | kr = bootstrap_check_in(bootstrap_port, service, &mp);
|
---|
370 | if (kr == KERN_SUCCESS)
|
---|
371 | return mp;
|
---|
372 |
|
---|
373 | #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
|
---|
374 | /* Pre SnowLeopard version */
|
---|
375 | kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
|
---|
376 | if (kr != KERN_SUCCESS)
|
---|
377 | return MACH_PORT_NULL;
|
---|
378 |
|
---|
379 | kr = mach_port_insert_right(mach_task_self(), mp, mp,
|
---|
380 | MACH_MSG_TYPE_MAKE_SEND);
|
---|
381 | if (kr != KERN_SUCCESS) {
|
---|
382 | mach_port_destroy(mach_task_self(), mp);
|
---|
383 | return MACH_PORT_NULL;
|
---|
384 | }
|
---|
385 |
|
---|
386 | kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp);
|
---|
387 | if (kr != KERN_SUCCESS) {
|
---|
388 | mach_port_destroy(mach_task_self(), mp);
|
---|
389 | return MACH_PORT_NULL;
|
---|
390 | }
|
---|
391 |
|
---|
392 | return mp;
|
---|
393 | #else
|
---|
394 | return MACH_PORT_NULL;
|
---|
395 | #endif
|
---|
396 | }
|
---|
397 |
|
---|
398 |
|
---|
399 | #endif /* __APPLE__ && HAVE_GCD */
|
---|
400 |
|
---|
401 |
|
---|
402 | int
|
---|
403 | heim_sipc_launchd_mach_init(const char *service,
|
---|
404 | heim_ipc_callback callback,
|
---|
405 | void *user, heim_sipc *ctx)
|
---|
406 | {
|
---|
407 | #if defined(__APPLE__) && defined(HAVE_GCD)
|
---|
408 | mach_port_t sport = MACH_PORT_NULL;
|
---|
409 | heim_sipc c = NULL;
|
---|
410 | int ret;
|
---|
411 |
|
---|
412 | *ctx = NULL;
|
---|
413 |
|
---|
414 | sport = mach_checkin_or_register(service);
|
---|
415 | if (sport == MACH_PORT_NULL) {
|
---|
416 | ret = ENOENT;
|
---|
417 | goto error;
|
---|
418 | }
|
---|
419 |
|
---|
420 | c = calloc(1, sizeof(*c));
|
---|
421 | if (c == NULL) {
|
---|
422 | ret = ENOMEM;
|
---|
423 | goto error;
|
---|
424 | }
|
---|
425 | c->release = mach_release;
|
---|
426 | c->userctx = user;
|
---|
427 | c->callback = callback;
|
---|
428 |
|
---|
429 | ret = mach_init(service, sport, c);
|
---|
430 | if (ret)
|
---|
431 | goto error;
|
---|
432 |
|
---|
433 | *ctx = c;
|
---|
434 | return 0;
|
---|
435 | error:
|
---|
436 | if (c)
|
---|
437 | free(c);
|
---|
438 | if (sport != MACH_PORT_NULL)
|
---|
439 | mach_port_mod_refs(mach_task_self(), sport,
|
---|
440 | MACH_PORT_RIGHT_RECEIVE, -1);
|
---|
441 | return ret;
|
---|
442 | #else /* !(__APPLE__ && HAVE_GCD) */
|
---|
443 | *ctx = NULL;
|
---|
444 | return EINVAL;
|
---|
445 | #endif /* __APPLE__ && HAVE_GCD */
|
---|
446 | }
|
---|
447 |
|
---|
448 | struct client {
|
---|
449 | int fd;
|
---|
450 | heim_ipc_callback callback;
|
---|
451 | void *userctx;
|
---|
452 | int flags;
|
---|
453 | #define LISTEN_SOCKET 1
|
---|
454 | #define WAITING_READ 2
|
---|
455 | #define WAITING_WRITE 4
|
---|
456 | #define WAITING_CLOSE 8
|
---|
457 |
|
---|
458 | #define HTTP_REPLY 16
|
---|
459 |
|
---|
460 | #define INHERIT_MASK 0xffff0000
|
---|
461 | #define INCLUDE_ERROR_CODE (1 << 16)
|
---|
462 | #define ALLOW_HTTP (1<<17)
|
---|
463 | #define UNIX_SOCKET (1<<18)
|
---|
464 | unsigned calls;
|
---|
465 | size_t ptr, len;
|
---|
466 | uint8_t *inmsg;
|
---|
467 | size_t olen;
|
---|
468 | uint8_t *outmsg;
|
---|
469 | #ifdef HAVE_GCD
|
---|
470 | dispatch_source_t in;
|
---|
471 | dispatch_source_t out;
|
---|
472 | #endif
|
---|
473 | struct {
|
---|
474 | uid_t uid;
|
---|
475 | gid_t gid;
|
---|
476 | pid_t pid;
|
---|
477 | } unixrights;
|
---|
478 | };
|
---|
479 |
|
---|
480 | #ifndef HAVE_GCD
|
---|
481 | static unsigned num_clients = 0;
|
---|
482 | static struct client **clients = NULL;
|
---|
483 | #endif
|
---|
484 |
|
---|
485 | static void handle_read(struct client *);
|
---|
486 | static void handle_write(struct client *);
|
---|
487 | static int maybe_close(struct client *);
|
---|
488 |
|
---|
489 | /*
|
---|
490 | * Update peer credentials from socket.
|
---|
491 | *
|
---|
492 | * SCM_CREDS can only be updated the first time there is read data to
|
---|
493 | * read from the filedescriptor, so if we read do it before this
|
---|
494 | * point, the cred data might not be is not there yet.
|
---|
495 | */
|
---|
496 |
|
---|
497 | static int
|
---|
498 | update_client_creds(struct client *c)
|
---|
499 | {
|
---|
500 | #ifdef HAVE_GETPEERUCRED
|
---|
501 | /* Solaris 10 */
|
---|
502 | {
|
---|
503 | ucred_t *peercred;
|
---|
504 |
|
---|
505 | if (getpeerucred(c->fd, &peercred) != 0) {
|
---|
506 | c->unixrights.uid = ucred_geteuid(peercred);
|
---|
507 | c->unixrights.gid = ucred_getegid(peercred);
|
---|
508 | c->unixrights.pid = 0;
|
---|
509 | ucred_free(peercred);
|
---|
510 | return 1;
|
---|
511 | }
|
---|
512 | }
|
---|
513 | #endif
|
---|
514 | #ifdef HAVE_GETPEEREID
|
---|
515 | /* FreeBSD, OpenBSD */
|
---|
516 | {
|
---|
517 | uid_t uid;
|
---|
518 | gid_t gid;
|
---|
519 |
|
---|
520 | if (getpeereid(c->fd, &uid, &gid) == 0) {
|
---|
521 | c->unixrights.uid = uid;
|
---|
522 | c->unixrights.gid = gid;
|
---|
523 | c->unixrights.pid = 0;
|
---|
524 | return 1;
|
---|
525 | }
|
---|
526 | }
|
---|
527 | #endif
|
---|
528 | #ifdef SO_PEERCRED
|
---|
529 | /* Linux */
|
---|
530 | {
|
---|
531 | struct ucred pc;
|
---|
532 | socklen_t pclen = sizeof(pc);
|
---|
533 |
|
---|
534 | if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
|
---|
535 | c->unixrights.uid = pc.uid;
|
---|
536 | c->unixrights.gid = pc.gid;
|
---|
537 | c->unixrights.pid = pc.pid;
|
---|
538 | return 1;
|
---|
539 | }
|
---|
540 | }
|
---|
541 | #endif
|
---|
542 | #if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
|
---|
543 | {
|
---|
544 | struct xucred peercred;
|
---|
545 | socklen_t peercredlen = sizeof(peercred);
|
---|
546 |
|
---|
547 | if (getsockopt(c->fd, LOCAL_PEERCRED, 1,
|
---|
548 | (void *)&peercred, &peercredlen) == 0
|
---|
549 | && peercred.cr_version == XUCRED_VERSION)
|
---|
550 | {
|
---|
551 | c->unixrights.uid = peercred.cr_uid;
|
---|
552 | c->unixrights.gid = peercred.cr_gid;
|
---|
553 | c->unixrights.pid = 0;
|
---|
554 | return 1;
|
---|
555 | }
|
---|
556 | }
|
---|
557 | #endif
|
---|
558 | #if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
|
---|
559 | /* NetBSD */
|
---|
560 | if (c->unixrights.uid == (uid_t)-1) {
|
---|
561 | struct msghdr msg;
|
---|
562 | socklen_t crmsgsize;
|
---|
563 | void *crmsg;
|
---|
564 | struct cmsghdr *cmp;
|
---|
565 | struct sockcred *sc;
|
---|
566 |
|
---|
567 | memset(&msg, 0, sizeof(msg));
|
---|
568 | crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
|
---|
569 | if (crmsgsize == 0)
|
---|
570 | return 1 ;
|
---|
571 |
|
---|
572 | crmsg = malloc(crmsgsize);
|
---|
573 | if (crmsg == NULL)
|
---|
574 | goto failed_scm_creds;
|
---|
575 |
|
---|
576 | memset(crmsg, 0, crmsgsize);
|
---|
577 |
|
---|
578 | msg.msg_control = crmsg;
|
---|
579 | msg.msg_controllen = crmsgsize;
|
---|
580 |
|
---|
581 | if (recvmsg(c->fd, &msg, 0) < 0) {
|
---|
582 | free(crmsg);
|
---|
583 | goto failed_scm_creds;
|
---|
584 | }
|
---|
585 |
|
---|
586 | if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
|
---|
587 | free(crmsg);
|
---|
588 | goto failed_scm_creds;
|
---|
589 | }
|
---|
590 |
|
---|
591 | cmp = CMSG_FIRSTHDR(&msg);
|
---|
592 | if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
|
---|
593 | free(crmsg);
|
---|
594 | goto failed_scm_creds;
|
---|
595 | }
|
---|
596 |
|
---|
597 | sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
|
---|
598 |
|
---|
599 | c->unixrights.uid = sc->sc_euid;
|
---|
600 | c->unixrights.gid = sc->sc_egid;
|
---|
601 | c->unixrights.pid = 0;
|
---|
602 |
|
---|
603 | free(crmsg);
|
---|
604 | return 1;
|
---|
605 | } else {
|
---|
606 | /* we already got the cred, just return it */
|
---|
607 | return 1;
|
---|
608 | }
|
---|
609 | failed_scm_creds:
|
---|
610 | #endif
|
---|
611 | return 0;
|
---|
612 | }
|
---|
613 |
|
---|
614 |
|
---|
615 | static struct client *
|
---|
616 | add_new_socket(int fd,
|
---|
617 | int flags,
|
---|
618 | heim_ipc_callback callback,
|
---|
619 | void *userctx)
|
---|
620 | {
|
---|
621 | struct client *c;
|
---|
622 | int fileflags;
|
---|
623 |
|
---|
624 | c = calloc(1, sizeof(*c));
|
---|
625 | if (c == NULL)
|
---|
626 | return NULL;
|
---|
627 |
|
---|
628 | if (flags & LISTEN_SOCKET) {
|
---|
629 | c->fd = fd;
|
---|
630 | } else {
|
---|
631 | c->fd = accept(fd, NULL, NULL);
|
---|
632 | if(c->fd < 0) {
|
---|
633 | free(c);
|
---|
634 | return NULL;
|
---|
635 | }
|
---|
636 | }
|
---|
637 |
|
---|
638 | c->flags = flags;
|
---|
639 | c->callback = callback;
|
---|
640 | c->userctx = userctx;
|
---|
641 |
|
---|
642 | fileflags = fcntl(c->fd, F_GETFL, 0);
|
---|
643 | fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK);
|
---|
644 |
|
---|
645 | #ifdef HAVE_GCD
|
---|
646 | init_globals();
|
---|
647 |
|
---|
648 | c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
|
---|
649 | c->fd, 0, eventq);
|
---|
650 | c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
|
---|
651 | c->fd, 0, eventq);
|
---|
652 |
|
---|
653 | dispatch_source_set_event_handler(c->in, ^{
|
---|
654 | int rw = (c->flags & WAITING_WRITE);
|
---|
655 | handle_read(c);
|
---|
656 | if (rw == 0 && (c->flags & WAITING_WRITE))
|
---|
657 | dispatch_resume(c->out);
|
---|
658 | if ((c->flags & WAITING_READ) == 0)
|
---|
659 | dispatch_suspend(c->in);
|
---|
660 | maybe_close(c);
|
---|
661 | });
|
---|
662 | dispatch_source_set_event_handler(c->out, ^{
|
---|
663 | handle_write(c);
|
---|
664 | if ((c->flags & WAITING_WRITE) == 0) {
|
---|
665 | dispatch_suspend(c->out);
|
---|
666 | }
|
---|
667 | maybe_close(c);
|
---|
668 | });
|
---|
669 |
|
---|
670 | dispatch_resume(c->in);
|
---|
671 | #else
|
---|
672 | clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1));
|
---|
673 | clients[num_clients] = c;
|
---|
674 | num_clients++;
|
---|
675 | #endif
|
---|
676 |
|
---|
677 | return c;
|
---|
678 | }
|
---|
679 |
|
---|
680 | static int
|
---|
681 | maybe_close(struct client *c)
|
---|
682 | {
|
---|
683 | if (c->calls != 0)
|
---|
684 | return 0;
|
---|
685 | if (c->flags & (WAITING_READ|WAITING_WRITE))
|
---|
686 | return 0;
|
---|
687 |
|
---|
688 | #ifdef HAVE_GCD
|
---|
689 | dispatch_source_cancel(c->in);
|
---|
690 | if ((c->flags & WAITING_READ) == 0)
|
---|
691 | dispatch_resume(c->in);
|
---|
692 | dispatch_release(c->in);
|
---|
693 |
|
---|
694 | dispatch_source_cancel(c->out);
|
---|
695 | if ((c->flags & WAITING_WRITE) == 0)
|
---|
696 | dispatch_resume(c->out);
|
---|
697 | dispatch_release(c->out);
|
---|
698 | #endif
|
---|
699 | close(c->fd); /* ref count fd close */
|
---|
700 | free(c);
|
---|
701 | return 1;
|
---|
702 | }
|
---|
703 |
|
---|
704 |
|
---|
705 | struct socket_call {
|
---|
706 | heim_idata in;
|
---|
707 | struct client *c;
|
---|
708 | heim_icred cred;
|
---|
709 | };
|
---|
710 |
|
---|
711 | static void
|
---|
712 | output_data(struct client *c, const void *data, size_t len)
|
---|
713 | {
|
---|
714 | if (c->olen + len < c->olen)
|
---|
715 | abort();
|
---|
716 | c->outmsg = erealloc(c->outmsg, c->olen + len);
|
---|
717 | memcpy(&c->outmsg[c->olen], data, len);
|
---|
718 | c->olen += len;
|
---|
719 | c->flags |= WAITING_WRITE;
|
---|
720 | }
|
---|
721 |
|
---|
722 | static void
|
---|
723 | socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
---|
724 | {
|
---|
725 | struct socket_call *sc = (struct socket_call *)ctx;
|
---|
726 | struct client *c = sc->c;
|
---|
727 |
|
---|
728 | /* double complete ? */
|
---|
729 | if (c == NULL)
|
---|
730 | abort();
|
---|
731 |
|
---|
732 | if ((c->flags & WAITING_CLOSE) == 0) {
|
---|
733 | uint32_t u32;
|
---|
734 |
|
---|
735 | /* length */
|
---|
736 | u32 = htonl(reply->length);
|
---|
737 | output_data(c, &u32, sizeof(u32));
|
---|
738 |
|
---|
739 | /* return value */
|
---|
740 | if (c->flags & INCLUDE_ERROR_CODE) {
|
---|
741 | u32 = htonl(returnvalue);
|
---|
742 | output_data(c, &u32, sizeof(u32));
|
---|
743 | }
|
---|
744 |
|
---|
745 | /* data */
|
---|
746 | output_data(c, reply->data, reply->length);
|
---|
747 |
|
---|
748 | /* if HTTP, close connection */
|
---|
749 | if (c->flags & HTTP_REPLY) {
|
---|
750 | c->flags |= WAITING_CLOSE;
|
---|
751 | c->flags &= ~WAITING_READ;
|
---|
752 | }
|
---|
753 | }
|
---|
754 |
|
---|
755 | c->calls--;
|
---|
756 | if (sc->cred)
|
---|
757 | heim_ipc_free_cred(sc->cred);
|
---|
758 | free(sc->in.data);
|
---|
759 | sc->c = NULL; /* so we can catch double complete */
|
---|
760 | free(sc);
|
---|
761 |
|
---|
762 | maybe_close(c);
|
---|
763 | }
|
---|
764 |
|
---|
765 | /* remove HTTP %-quoting from buf */
|
---|
766 | static int
|
---|
767 | de_http(char *buf)
|
---|
768 | {
|
---|
769 | unsigned char *p, *q;
|
---|
770 | for(p = q = (unsigned char *)buf; *p; p++, q++) {
|
---|
771 | if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
|
---|
772 | unsigned int x;
|
---|
773 | if(sscanf((char *)p + 1, "%2x", &x) != 1)
|
---|
774 | return -1;
|
---|
775 | *q = x;
|
---|
776 | p += 2;
|
---|
777 | } else
|
---|
778 | *q = *p;
|
---|
779 | }
|
---|
780 | *q = '\0';
|
---|
781 | return 0;
|
---|
782 | }
|
---|
783 |
|
---|
784 | static struct socket_call *
|
---|
785 | handle_http_tcp(struct client *c)
|
---|
786 | {
|
---|
787 | struct socket_call *cs;
|
---|
788 | char *s, *p, *t;
|
---|
789 | void *data;
|
---|
790 | char *proto;
|
---|
791 | int len;
|
---|
792 |
|
---|
793 | s = (char *)c->inmsg;
|
---|
794 |
|
---|
795 | p = strstr(s, "\r\n");
|
---|
796 | if (p == NULL)
|
---|
797 | return NULL;
|
---|
798 |
|
---|
799 | *p = 0;
|
---|
800 |
|
---|
801 | p = NULL;
|
---|
802 | t = strtok_r(s, " \t", &p);
|
---|
803 | if (t == NULL)
|
---|
804 | return NULL;
|
---|
805 |
|
---|
806 | t = strtok_r(NULL, " \t", &p);
|
---|
807 | if (t == NULL)
|
---|
808 | return NULL;
|
---|
809 |
|
---|
810 | data = malloc(strlen(t));
|
---|
811 | if (data == NULL)
|
---|
812 | return NULL;
|
---|
813 |
|
---|
814 | if(*t == '/')
|
---|
815 | t++;
|
---|
816 | if(de_http(t) != 0) {
|
---|
817 | free(data);
|
---|
818 | return NULL;
|
---|
819 | }
|
---|
820 | proto = strtok_r(NULL, " \t", &p);
|
---|
821 | if (proto == NULL) {
|
---|
822 | free(data);
|
---|
823 | return NULL;
|
---|
824 | }
|
---|
825 | len = base64_decode(t, data);
|
---|
826 | if(len <= 0){
|
---|
827 | const char *msg =
|
---|
828 | " 404 Not found\r\n"
|
---|
829 | "Server: Heimdal/" VERSION "\r\n"
|
---|
830 | "Cache-Control: no-cache\r\n"
|
---|
831 | "Pragma: no-cache\r\n"
|
---|
832 | "Content-type: text/html\r\n"
|
---|
833 | "Content-transfer-encoding: 8bit\r\n\r\n"
|
---|
834 | "<TITLE>404 Not found</TITLE>\r\n"
|
---|
835 | "<H1>404 Not found</H1>\r\n"
|
---|
836 | "That page doesn't exist, maybe you are looking for "
|
---|
837 | "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
|
---|
838 | free(data);
|
---|
839 | output_data(c, proto, strlen(proto));
|
---|
840 | output_data(c, msg, strlen(msg));
|
---|
841 | return NULL;
|
---|
842 | }
|
---|
843 |
|
---|
844 | cs = emalloc(sizeof(*cs));
|
---|
845 | cs->c = c;
|
---|
846 | cs->in.data = data;
|
---|
847 | cs->in.length = len;
|
---|
848 | c->ptr = 0;
|
---|
849 |
|
---|
850 | {
|
---|
851 | const char *msg =
|
---|
852 | " 200 OK\r\n"
|
---|
853 | "Server: Heimdal/" VERSION "\r\n"
|
---|
854 | "Cache-Control: no-cache\r\n"
|
---|
855 | "Pragma: no-cache\r\n"
|
---|
856 | "Content-type: application/octet-stream\r\n"
|
---|
857 | "Content-transfer-encoding: binary\r\n\r\n";
|
---|
858 | output_data(c, proto, strlen(proto));
|
---|
859 | output_data(c, msg, strlen(msg));
|
---|
860 | }
|
---|
861 |
|
---|
862 | return cs;
|
---|
863 | }
|
---|
864 |
|
---|
865 |
|
---|
866 | static void
|
---|
867 | handle_read(struct client *c)
|
---|
868 | {
|
---|
869 | ssize_t len;
|
---|
870 | uint32_t dlen;
|
---|
871 |
|
---|
872 | if (c->flags & LISTEN_SOCKET) {
|
---|
873 | add_new_socket(c->fd,
|
---|
874 | WAITING_READ | (c->flags & INHERIT_MASK),
|
---|
875 | c->callback,
|
---|
876 | c->userctx);
|
---|
877 | return;
|
---|
878 | }
|
---|
879 |
|
---|
880 | if (c->ptr - c->len < 1024) {
|
---|
881 | c->inmsg = erealloc(c->inmsg,
|
---|
882 | c->len + 1024);
|
---|
883 | c->len += 1024;
|
---|
884 | }
|
---|
885 |
|
---|
886 | len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr);
|
---|
887 | if (len <= 0) {
|
---|
888 | c->flags |= WAITING_CLOSE;
|
---|
889 | c->flags &= ~WAITING_READ;
|
---|
890 | return;
|
---|
891 | }
|
---|
892 | c->ptr += len;
|
---|
893 | if (c->ptr > c->len)
|
---|
894 | abort();
|
---|
895 |
|
---|
896 | while (c->ptr >= sizeof(dlen)) {
|
---|
897 | struct socket_call *cs;
|
---|
898 |
|
---|
899 | if((c->flags & ALLOW_HTTP) && c->ptr >= 4 &&
|
---|
900 | strncmp((char *)c->inmsg, "GET ", 4) == 0 &&
|
---|
901 | strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) {
|
---|
902 |
|
---|
903 | /* remove the trailing \r\n\r\n so the string is NUL terminated */
|
---|
904 | c->inmsg[c->ptr - 4] = '\0';
|
---|
905 |
|
---|
906 | c->flags |= HTTP_REPLY;
|
---|
907 |
|
---|
908 | cs = handle_http_tcp(c);
|
---|
909 | if (cs == NULL) {
|
---|
910 | c->flags |= WAITING_CLOSE;
|
---|
911 | c->flags &= ~WAITING_READ;
|
---|
912 | break;
|
---|
913 | }
|
---|
914 | } else {
|
---|
915 | memcpy(&dlen, c->inmsg, sizeof(dlen));
|
---|
916 | dlen = ntohl(dlen);
|
---|
917 |
|
---|
918 | if (dlen > MAX_PACKET_SIZE) {
|
---|
919 | c->flags |= WAITING_CLOSE;
|
---|
920 | c->flags &= ~WAITING_READ;
|
---|
921 | return;
|
---|
922 | }
|
---|
923 | if (dlen > c->ptr - sizeof(dlen)) {
|
---|
924 | break;
|
---|
925 | }
|
---|
926 |
|
---|
927 | cs = emalloc(sizeof(*cs));
|
---|
928 | cs->c = c;
|
---|
929 | cs->in.data = emalloc(dlen);
|
---|
930 | memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
|
---|
931 | cs->in.length = dlen;
|
---|
932 |
|
---|
933 | c->ptr -= sizeof(dlen) + dlen;
|
---|
934 | memmove(c->inmsg,
|
---|
935 | c->inmsg + sizeof(dlen) + dlen,
|
---|
936 | c->ptr);
|
---|
937 | }
|
---|
938 |
|
---|
939 | c->calls++;
|
---|
940 |
|
---|
941 | if ((c->flags & UNIX_SOCKET) != 0) {
|
---|
942 | if (update_client_creds(c))
|
---|
943 | _heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid,
|
---|
944 | c->unixrights.pid, -1, &cs->cred);
|
---|
945 | }
|
---|
946 |
|
---|
947 | c->callback(c->userctx, &cs->in,
|
---|
948 | cs->cred, socket_complete,
|
---|
949 | (heim_sipc_call)cs);
|
---|
950 | }
|
---|
951 | }
|
---|
952 |
|
---|
953 | static void
|
---|
954 | handle_write(struct client *c)
|
---|
955 | {
|
---|
956 | ssize_t len;
|
---|
957 |
|
---|
958 | len = write(c->fd, c->outmsg, c->olen);
|
---|
959 | if (len <= 0) {
|
---|
960 | c->flags |= WAITING_CLOSE;
|
---|
961 | c->flags &= ~(WAITING_WRITE);
|
---|
962 | } else if (c->olen != (size_t)len) {
|
---|
963 | memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len);
|
---|
964 | c->olen -= len;
|
---|
965 | } else {
|
---|
966 | c->olen = 0;
|
---|
967 | free(c->outmsg);
|
---|
968 | c->outmsg = NULL;
|
---|
969 | c->flags &= ~(WAITING_WRITE);
|
---|
970 | }
|
---|
971 | }
|
---|
972 |
|
---|
973 |
|
---|
974 | #ifndef HAVE_GCD
|
---|
975 |
|
---|
976 | static void
|
---|
977 | process_loop(void)
|
---|
978 | {
|
---|
979 | struct pollfd *fds;
|
---|
980 | unsigned n;
|
---|
981 | unsigned num_fds;
|
---|
982 |
|
---|
983 | while(num_clients > 0) {
|
---|
984 |
|
---|
985 | fds = malloc(num_clients * sizeof(fds[0]));
|
---|
986 | if(fds == NULL)
|
---|
987 | abort();
|
---|
988 |
|
---|
989 | num_fds = num_clients;
|
---|
990 |
|
---|
991 | for (n = 0 ; n < num_fds; n++) {
|
---|
992 | fds[n].fd = clients[n]->fd;
|
---|
993 | fds[n].events = 0;
|
---|
994 | if (clients[n]->flags & WAITING_READ)
|
---|
995 | fds[n].events |= POLLIN;
|
---|
996 | if (clients[n]->flags & WAITING_WRITE)
|
---|
997 | fds[n].events |= POLLOUT;
|
---|
998 |
|
---|
999 | fds[n].revents = 0;
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | poll(fds, num_fds, -1);
|
---|
1003 |
|
---|
1004 | for (n = 0 ; n < num_fds; n++) {
|
---|
1005 | if (clients[n] == NULL)
|
---|
1006 | continue;
|
---|
1007 | if (fds[n].revents & POLLERR) {
|
---|
1008 | clients[n]->flags |= WAITING_CLOSE;
|
---|
1009 | continue;
|
---|
1010 | }
|
---|
1011 |
|
---|
1012 | if (fds[n].revents & POLLIN)
|
---|
1013 | handle_read(clients[n]);
|
---|
1014 | if (fds[n].revents & POLLOUT)
|
---|
1015 | handle_write(clients[n]);
|
---|
1016 | }
|
---|
1017 |
|
---|
1018 | n = 0;
|
---|
1019 | while (n < num_clients) {
|
---|
1020 | struct client *c = clients[n];
|
---|
1021 | if (maybe_close(c)) {
|
---|
1022 | if (n < num_clients - 1)
|
---|
1023 | clients[n] = clients[num_clients - 1];
|
---|
1024 | num_clients--;
|
---|
1025 | } else
|
---|
1026 | n++;
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | free(fds);
|
---|
1030 | }
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | #endif
|
---|
1034 |
|
---|
1035 | static int
|
---|
1036 | socket_release(heim_sipc ctx)
|
---|
1037 | {
|
---|
1038 | struct client *c = ctx->mech;
|
---|
1039 | c->flags |= WAITING_CLOSE;
|
---|
1040 | return 0;
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | int
|
---|
1044 | heim_sipc_stream_listener(int fd, int type,
|
---|
1045 | heim_ipc_callback callback,
|
---|
1046 | void *user, heim_sipc *ctx)
|
---|
1047 | {
|
---|
1048 | heim_sipc ct = calloc(1, sizeof(*ct));
|
---|
1049 | struct client *c;
|
---|
1050 |
|
---|
1051 | if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP)))
|
---|
1052 | return EINVAL;
|
---|
1053 |
|
---|
1054 | switch (type) {
|
---|
1055 | case HEIM_SIPC_TYPE_IPC:
|
---|
1056 | c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user);
|
---|
1057 | break;
|
---|
1058 | case HEIM_SIPC_TYPE_UINT32:
|
---|
1059 | c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
|
---|
1060 | break;
|
---|
1061 | case HEIM_SIPC_TYPE_HTTP:
|
---|
1062 | case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP:
|
---|
1063 | c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user);
|
---|
1064 | break;
|
---|
1065 | default:
|
---|
1066 | free(ct);
|
---|
1067 | return EINVAL;
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | ct->mech = c;
|
---|
1071 | ct->release = socket_release;
|
---|
1072 |
|
---|
1073 | c->unixrights.uid = (uid_t) -1;
|
---|
1074 | c->unixrights.gid = (gid_t) -1;
|
---|
1075 | c->unixrights.pid = (pid_t) 0;
|
---|
1076 |
|
---|
1077 | *ctx = ct;
|
---|
1078 | return 0;
|
---|
1079 | }
|
---|
1080 |
|
---|
1081 | int
|
---|
1082 | heim_sipc_service_unix(const char *service,
|
---|
1083 | heim_ipc_callback callback,
|
---|
1084 | void *user, heim_sipc *ctx)
|
---|
1085 | {
|
---|
1086 | struct sockaddr_un un;
|
---|
1087 | int fd, ret;
|
---|
1088 |
|
---|
1089 | un.sun_family = AF_UNIX;
|
---|
1090 |
|
---|
1091 | snprintf(un.sun_path, sizeof(un.sun_path),
|
---|
1092 | "/var/run/.heim_%s-socket", service);
|
---|
1093 | fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
---|
1094 | if (fd < 0)
|
---|
1095 | return errno;
|
---|
1096 |
|
---|
1097 | socket_set_reuseaddr(fd, 1);
|
---|
1098 | #ifdef LOCAL_CREDS
|
---|
1099 | {
|
---|
1100 | int one = 1;
|
---|
1101 | setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
|
---|
1102 | }
|
---|
1103 | #endif
|
---|
1104 |
|
---|
1105 | unlink(un.sun_path);
|
---|
1106 |
|
---|
1107 | if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
|
---|
1108 | close(fd);
|
---|
1109 | return errno;
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | if (listen(fd, SOMAXCONN) < 0) {
|
---|
1113 | close(fd);
|
---|
1114 | return errno;
|
---|
1115 | }
|
---|
1116 |
|
---|
1117 | chmod(un.sun_path, 0666);
|
---|
1118 |
|
---|
1119 | ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
|
---|
1120 | callback, user, ctx);
|
---|
1121 | if (ret == 0) {
|
---|
1122 | struct client *c = (*ctx)->mech;
|
---|
1123 | c->flags |= UNIX_SOCKET;
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | return ret;
|
---|
1127 | }
|
---|
1128 |
|
---|
1129 | /**
|
---|
1130 | * Set the idle timeout value
|
---|
1131 |
|
---|
1132 | * The timeout event handler is triggered recurrently every idle
|
---|
1133 | * period `t'. The default action is rather draconian and just calls
|
---|
1134 | * exit(0), so you might want to change this to something more
|
---|
1135 | * graceful using heim_sipc_set_timeout_handler().
|
---|
1136 | */
|
---|
1137 |
|
---|
1138 | void
|
---|
1139 | heim_sipc_timeout(time_t t)
|
---|
1140 | {
|
---|
1141 | #ifdef HAVE_GCD
|
---|
1142 | static dispatch_once_t timeoutonce;
|
---|
1143 | init_globals();
|
---|
1144 | dispatch_sync(timerq, ^{
|
---|
1145 | timeoutvalue = t;
|
---|
1146 | set_timer();
|
---|
1147 | });
|
---|
1148 | dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); });
|
---|
1149 | #else
|
---|
1150 | abort();
|
---|
1151 | #endif
|
---|
1152 | }
|
---|
1153 |
|
---|
1154 | /**
|
---|
1155 | * Set the timeout event handler
|
---|
1156 | *
|
---|
1157 | * Replaces the default idle timeout action.
|
---|
1158 | */
|
---|
1159 |
|
---|
1160 | void
|
---|
1161 | heim_sipc_set_timeout_handler(void (*func)(void))
|
---|
1162 | {
|
---|
1163 | #ifdef HAVE_GCD
|
---|
1164 | init_globals();
|
---|
1165 | dispatch_sync(timerq, ^{ timer_ev = func; });
|
---|
1166 | #else
|
---|
1167 | abort();
|
---|
1168 | #endif
|
---|
1169 | }
|
---|
1170 |
|
---|
1171 |
|
---|
1172 | void
|
---|
1173 | heim_sipc_free_context(heim_sipc ctx)
|
---|
1174 | {
|
---|
1175 | (ctx->release)(ctx);
|
---|
1176 | }
|
---|
1177 |
|
---|
1178 | void
|
---|
1179 | heim_ipc_main(void)
|
---|
1180 | {
|
---|
1181 | #ifdef HAVE_GCD
|
---|
1182 | dispatch_main();
|
---|
1183 | #else
|
---|
1184 | process_loop();
|
---|
1185 | #endif
|
---|
1186 | }
|
---|
1187 |
|
---|