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