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