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