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