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