xref: /minix3/crypto/external/bsd/heimdal/dist/lib/ipc/client.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: client.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 
40ebfedea0SLionel Sambuc #if defined(__APPLE__) && defined(HAVE_GCD)
41ebfedea0SLionel Sambuc 
42ebfedea0SLionel Sambuc #include "heim_ipc.h"
43ebfedea0SLionel Sambuc #include "heim_ipc_asyncServer.h"
44ebfedea0SLionel Sambuc 
45ebfedea0SLionel Sambuc #include <dispatch/dispatch.h>
46ebfedea0SLionel Sambuc #include <mach/mach.h>
47ebfedea0SLionel Sambuc 
48ebfedea0SLionel Sambuc static dispatch_once_t jobqinited = 0;
49ebfedea0SLionel Sambuc static dispatch_queue_t jobq = NULL;
50ebfedea0SLionel Sambuc static dispatch_queue_t syncq;
51ebfedea0SLionel Sambuc 
52ebfedea0SLionel Sambuc struct mach_ctx {
53ebfedea0SLionel Sambuc     mach_port_t server;
54ebfedea0SLionel Sambuc     char *name;
55ebfedea0SLionel Sambuc };
56ebfedea0SLionel Sambuc 
57ebfedea0SLionel Sambuc static int
58ebfedea0SLionel Sambuc mach_release(void *ctx);
59ebfedea0SLionel Sambuc 
60ebfedea0SLionel Sambuc static int
mach_init(const char * service,void ** ctx)61ebfedea0SLionel Sambuc mach_init(const char *service, void **ctx)
62ebfedea0SLionel Sambuc {
63ebfedea0SLionel Sambuc     struct mach_ctx *ipc;
64ebfedea0SLionel Sambuc     mach_port_t sport;
65ebfedea0SLionel Sambuc     int ret;
66ebfedea0SLionel Sambuc 
67ebfedea0SLionel Sambuc     dispatch_once(&jobqinited, ^{
68ebfedea0SLionel Sambuc 	    jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
69ebfedea0SLionel Sambuc 	    syncq = dispatch_queue_create("heim-ipc-syncq", NULL);
70ebfedea0SLionel Sambuc 	});
71ebfedea0SLionel Sambuc 
72ebfedea0SLionel Sambuc     ret = bootstrap_look_up(bootstrap_port, service, &sport);
73ebfedea0SLionel Sambuc     if (ret)
74ebfedea0SLionel Sambuc 	return ret;
75ebfedea0SLionel Sambuc 
76ebfedea0SLionel Sambuc     ipc = malloc(sizeof(*ipc));
77ebfedea0SLionel Sambuc     if (ipc == NULL) {
78ebfedea0SLionel Sambuc 	mach_port_destroy(mach_task_self(), sport);
79ebfedea0SLionel Sambuc 	return ENOMEM;
80ebfedea0SLionel Sambuc     }
81ebfedea0SLionel Sambuc 
82ebfedea0SLionel Sambuc     ipc->server = sport;
83ebfedea0SLionel Sambuc     ipc->name = strdup(service);
84ebfedea0SLionel Sambuc     if (ipc->name == NULL) {
85ebfedea0SLionel Sambuc 	mach_release(ipc);
86ebfedea0SLionel Sambuc 	return ENOMEM;
87ebfedea0SLionel Sambuc     }
88ebfedea0SLionel Sambuc 
89ebfedea0SLionel Sambuc     *ctx = ipc;
90ebfedea0SLionel Sambuc 
91ebfedea0SLionel Sambuc     return 0;
92ebfedea0SLionel Sambuc }
93ebfedea0SLionel Sambuc 
94ebfedea0SLionel Sambuc static int
mach_ipc(void * ctx,const heim_idata * request,heim_idata * response,heim_icred * cred)95ebfedea0SLionel Sambuc mach_ipc(void *ctx,
96ebfedea0SLionel Sambuc 	 const heim_idata *request, heim_idata *response,
97ebfedea0SLionel Sambuc 	 heim_icred *cred)
98ebfedea0SLionel Sambuc {
99ebfedea0SLionel Sambuc     struct mach_ctx *ipc = ctx;
100ebfedea0SLionel Sambuc     heim_ipc_message_inband_t requestin;
101ebfedea0SLionel Sambuc     mach_msg_type_number_t requestin_length = 0;
102ebfedea0SLionel Sambuc     heim_ipc_message_outband_t requestout = NULL;
103ebfedea0SLionel Sambuc     mach_msg_type_number_t requestout_length = 0;
104ebfedea0SLionel Sambuc     heim_ipc_message_inband_t replyin;
105ebfedea0SLionel Sambuc     mach_msg_type_number_t replyin_length;
106ebfedea0SLionel Sambuc     heim_ipc_message_outband_t replyout;
107ebfedea0SLionel Sambuc     mach_msg_type_number_t replyout_length;
108ebfedea0SLionel Sambuc     int ret, errorcode, retries = 0;
109ebfedea0SLionel Sambuc 
110ebfedea0SLionel Sambuc     memcpy(requestin, request->data, request->length);
111ebfedea0SLionel Sambuc     requestin_length = request->length;
112ebfedea0SLionel Sambuc 
113ebfedea0SLionel Sambuc     while (retries < 2) {
114ebfedea0SLionel Sambuc 	__block mach_port_t sport;
115ebfedea0SLionel Sambuc 
116ebfedea0SLionel Sambuc 	dispatch_sync(syncq, ^{ sport = ipc->server; });
117ebfedea0SLionel Sambuc 
118ebfedea0SLionel Sambuc 	ret = mheim_ipc_call(sport,
119ebfedea0SLionel Sambuc 			     requestin, requestin_length,
120ebfedea0SLionel Sambuc 			     requestout, requestout_length,
121ebfedea0SLionel Sambuc 			     &errorcode,
122ebfedea0SLionel Sambuc 			     replyin, &replyin_length,
123ebfedea0SLionel Sambuc 			     &replyout, &replyout_length);
124ebfedea0SLionel Sambuc 	if (ret == MACH_SEND_INVALID_DEST) {
125ebfedea0SLionel Sambuc 	    mach_port_t nport;
126ebfedea0SLionel Sambuc 	    /* race other threads to get a new port */
127ebfedea0SLionel Sambuc 	    ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport);
128ebfedea0SLionel Sambuc 	    if (ret)
129ebfedea0SLionel Sambuc 		return ret;
130ebfedea0SLionel Sambuc 	    dispatch_sync(syncq, ^{
131ebfedea0SLionel Sambuc 		    /* check if we lost the race to lookup the port */
132ebfedea0SLionel Sambuc 		    if (sport != ipc->server) {
133ebfedea0SLionel Sambuc 			mach_port_deallocate(mach_task_self(), nport);
134ebfedea0SLionel Sambuc 		    } else {
135ebfedea0SLionel Sambuc 			mach_port_deallocate(mach_task_self(), ipc->server);
136ebfedea0SLionel Sambuc 			ipc->server = nport;
137ebfedea0SLionel Sambuc 		    }
138ebfedea0SLionel Sambuc 		});
139ebfedea0SLionel Sambuc 	    retries++;
140ebfedea0SLionel Sambuc 	} else if (ret) {
141ebfedea0SLionel Sambuc 	    return ret;
142ebfedea0SLionel Sambuc 	} else
143ebfedea0SLionel Sambuc 	    break;
144ebfedea0SLionel Sambuc     }
145ebfedea0SLionel Sambuc     if (retries >= 2)
146ebfedea0SLionel Sambuc 	return EINVAL;
147ebfedea0SLionel Sambuc 
148ebfedea0SLionel Sambuc     if (errorcode) {
149ebfedea0SLionel Sambuc 	if (replyout_length)
150ebfedea0SLionel Sambuc 	    vm_deallocate (mach_task_self (), (vm_address_t) replyout,
151ebfedea0SLionel Sambuc 			   replyout_length);
152ebfedea0SLionel Sambuc 	return errorcode;
153ebfedea0SLionel Sambuc     }
154ebfedea0SLionel Sambuc 
155ebfedea0SLionel Sambuc     if (replyout_length) {
156ebfedea0SLionel Sambuc 	response->data = malloc(replyout_length);
157ebfedea0SLionel Sambuc 	if (response->data == NULL) {
158ebfedea0SLionel Sambuc 	    vm_deallocate (mach_task_self (), (vm_address_t) replyout,
159ebfedea0SLionel Sambuc 			   replyout_length);
160ebfedea0SLionel Sambuc 	    return ENOMEM;
161ebfedea0SLionel Sambuc 	}
162ebfedea0SLionel Sambuc 	memcpy(response->data, replyout, replyout_length);
163ebfedea0SLionel Sambuc 	response->length = replyout_length;
164ebfedea0SLionel Sambuc 	vm_deallocate (mach_task_self (), (vm_address_t) replyout,
165ebfedea0SLionel Sambuc 		       replyout_length);
166ebfedea0SLionel Sambuc     } else {
167ebfedea0SLionel Sambuc 	response->data = malloc(replyin_length);
168ebfedea0SLionel Sambuc 	if (response->data == NULL)
169ebfedea0SLionel Sambuc 	    return ENOMEM;
170ebfedea0SLionel Sambuc 	memcpy(response->data, replyin, replyin_length);
171ebfedea0SLionel Sambuc 	response->length = replyin_length;
172ebfedea0SLionel Sambuc     }
173ebfedea0SLionel Sambuc 
174ebfedea0SLionel Sambuc     return 0;
175ebfedea0SLionel Sambuc }
176ebfedea0SLionel Sambuc 
177ebfedea0SLionel Sambuc struct async_client {
178ebfedea0SLionel Sambuc     mach_port_t mp;
179ebfedea0SLionel Sambuc     dispatch_source_t source;
180ebfedea0SLionel Sambuc     dispatch_queue_t queue;
181ebfedea0SLionel Sambuc     void (*func)(void *, int, heim_idata *, heim_icred);
182ebfedea0SLionel Sambuc     void *userctx;
183ebfedea0SLionel Sambuc };
184ebfedea0SLionel Sambuc 
185ebfedea0SLionel Sambuc kern_return_t
mheim_ado_acall_reply(mach_port_t server_port,audit_token_t client_creds,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)186ebfedea0SLionel Sambuc mheim_ado_acall_reply(mach_port_t server_port,
187ebfedea0SLionel Sambuc 		      audit_token_t client_creds,
188ebfedea0SLionel Sambuc 		      int returnvalue,
189ebfedea0SLionel Sambuc 		      heim_ipc_message_inband_t replyin,
190ebfedea0SLionel Sambuc 		      mach_msg_type_number_t replyinCnt,
191ebfedea0SLionel Sambuc 		      heim_ipc_message_outband_t replyout,
192ebfedea0SLionel Sambuc 		      mach_msg_type_number_t replyoutCnt)
193ebfedea0SLionel Sambuc {
194ebfedea0SLionel Sambuc     struct async_client *c = dispatch_get_context(dispatch_get_current_queue());
195ebfedea0SLionel Sambuc     heim_idata response;
196ebfedea0SLionel Sambuc 
197ebfedea0SLionel Sambuc     if (returnvalue) {
198ebfedea0SLionel Sambuc 	response.data = NULL;
199ebfedea0SLionel Sambuc 	response.length = 0;
200ebfedea0SLionel Sambuc     } else if (replyoutCnt) {
201ebfedea0SLionel Sambuc 	response.data = replyout;
202ebfedea0SLionel Sambuc 	response.length = replyoutCnt;
203ebfedea0SLionel Sambuc     } else {
204ebfedea0SLionel Sambuc 	response.data = replyin;
205ebfedea0SLionel Sambuc 	response.length = replyinCnt;
206ebfedea0SLionel Sambuc     }
207ebfedea0SLionel Sambuc 
208ebfedea0SLionel Sambuc     (*c->func)(c->userctx, returnvalue, &response, NULL);
209ebfedea0SLionel Sambuc 
210ebfedea0SLionel Sambuc     if (replyoutCnt)
211ebfedea0SLionel Sambuc 	vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt);
212ebfedea0SLionel Sambuc 
213ebfedea0SLionel Sambuc     dispatch_source_cancel(c->source);
214ebfedea0SLionel Sambuc 
215ebfedea0SLionel Sambuc     return 0;
216ebfedea0SLionel Sambuc 
217ebfedea0SLionel Sambuc 
218ebfedea0SLionel Sambuc }
219ebfedea0SLionel Sambuc 
220ebfedea0SLionel Sambuc 
221ebfedea0SLionel Sambuc static int
mach_async(void * ctx,const heim_idata * request,void * userctx,void (* func)(void *,int,heim_idata *,heim_icred))222ebfedea0SLionel Sambuc mach_async(void *ctx, const heim_idata *request, void *userctx,
223ebfedea0SLionel Sambuc 	   void (*func)(void *, int, heim_idata *, heim_icred))
224ebfedea0SLionel Sambuc {
225ebfedea0SLionel Sambuc     struct mach_ctx *ipc = ctx;
226ebfedea0SLionel Sambuc     heim_ipc_message_inband_t requestin;
227ebfedea0SLionel Sambuc     mach_msg_type_number_t requestin_length = 0;
228ebfedea0SLionel Sambuc     heim_ipc_message_outband_t requestout = NULL;
229ebfedea0SLionel Sambuc     mach_msg_type_number_t requestout_length = 0;
230ebfedea0SLionel Sambuc     int ret, retries = 0;
231ebfedea0SLionel Sambuc     kern_return_t kr;
232ebfedea0SLionel Sambuc     struct async_client *c;
233ebfedea0SLionel Sambuc 
234ebfedea0SLionel Sambuc     /* first create the service that will catch the reply from the server */
235ebfedea0SLionel Sambuc     /* XXX these object should be cached and reused */
236ebfedea0SLionel Sambuc 
237ebfedea0SLionel Sambuc     c = malloc(sizeof(*c));
238ebfedea0SLionel Sambuc     if (c == NULL)
239ebfedea0SLionel Sambuc 	return ENOMEM;
240ebfedea0SLionel Sambuc 
241ebfedea0SLionel Sambuc     kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp);
242ebfedea0SLionel Sambuc     if (kr != KERN_SUCCESS)
243ebfedea0SLionel Sambuc 	return EINVAL;
244ebfedea0SLionel Sambuc 
245ebfedea0SLionel Sambuc     c->queue = dispatch_queue_create("heim-ipc-async-client", NULL);
246ebfedea0SLionel Sambuc     c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue);
247ebfedea0SLionel Sambuc     dispatch_set_context(c->queue, c);
248ebfedea0SLionel Sambuc 
249ebfedea0SLionel Sambuc     dispatch_source_set_event_handler(c->source, ^{
250ebfedea0SLionel Sambuc 	    dispatch_mig_server(c->source,
251ebfedea0SLionel Sambuc 				sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem),
252ebfedea0SLionel Sambuc 				mheim_aipc_server);
253ebfedea0SLionel Sambuc 	});
254ebfedea0SLionel Sambuc 
255ebfedea0SLionel Sambuc     dispatch_source_set_cancel_handler(c->source, ^{
256ebfedea0SLionel Sambuc 	    mach_port_mod_refs(mach_task_self(), c->mp,
257ebfedea0SLionel Sambuc 			       MACH_PORT_RIGHT_RECEIVE, -1);
258ebfedea0SLionel Sambuc 	    dispatch_release(c->queue);
259ebfedea0SLionel Sambuc 	    dispatch_release(c->source);
260ebfedea0SLionel Sambuc 	    free(c);
261ebfedea0SLionel Sambuc 	});
262ebfedea0SLionel Sambuc 
263ebfedea0SLionel Sambuc     c->func = func;
264ebfedea0SLionel Sambuc     c->userctx = userctx;
265ebfedea0SLionel Sambuc 
266ebfedea0SLionel Sambuc     dispatch_resume(c->source);
267ebfedea0SLionel Sambuc 
268ebfedea0SLionel Sambuc     /* ok, send the message */
269ebfedea0SLionel Sambuc 
270ebfedea0SLionel Sambuc     memcpy(requestin, request->data, request->length);
271ebfedea0SLionel Sambuc     requestin_length = request->length;
272ebfedea0SLionel Sambuc 
273ebfedea0SLionel Sambuc     while (retries < 2) {
274ebfedea0SLionel Sambuc 	__block mach_port_t sport;
275ebfedea0SLionel Sambuc 
276ebfedea0SLionel Sambuc 	dispatch_sync(syncq, ^{ sport = ipc->server; });
277ebfedea0SLionel Sambuc 
278ebfedea0SLionel Sambuc 	ret = mheim_ipc_call_request(sport, c->mp,
279ebfedea0SLionel Sambuc 				     requestin, requestin_length,
280ebfedea0SLionel Sambuc 				     requestout, requestout_length);
281ebfedea0SLionel Sambuc 	if (ret == MACH_SEND_INVALID_DEST) {
282ebfedea0SLionel Sambuc 	    ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport);
283ebfedea0SLionel Sambuc 	    if (ret) {
284ebfedea0SLionel Sambuc 		dispatch_source_cancel(c->source);
285ebfedea0SLionel Sambuc 		return ret;
286ebfedea0SLionel Sambuc 	    }
287ebfedea0SLionel Sambuc 	    mach_port_deallocate(mach_task_self(), ipc->server);
288ebfedea0SLionel Sambuc 	    ipc->server = sport;
289ebfedea0SLionel Sambuc 	    retries++;
290ebfedea0SLionel Sambuc 	} else if (ret) {
291ebfedea0SLionel Sambuc 	    dispatch_source_cancel(c->source);
292ebfedea0SLionel Sambuc 	    return ret;
293ebfedea0SLionel Sambuc 	} else
294ebfedea0SLionel Sambuc 	    break;
295ebfedea0SLionel Sambuc     }
296ebfedea0SLionel Sambuc     if (retries >= 2) {
297ebfedea0SLionel Sambuc 	dispatch_source_cancel(c->source);
298ebfedea0SLionel Sambuc 	return EINVAL;
299ebfedea0SLionel Sambuc     }
300ebfedea0SLionel Sambuc 
301ebfedea0SLionel Sambuc     return 0;
302ebfedea0SLionel Sambuc }
303ebfedea0SLionel Sambuc 
304ebfedea0SLionel Sambuc static int
mach_release(void * ctx)305ebfedea0SLionel Sambuc mach_release(void *ctx)
306ebfedea0SLionel Sambuc {
307ebfedea0SLionel Sambuc     struct mach_ctx *ipc = ctx;
308ebfedea0SLionel Sambuc     if (ipc->server != MACH_PORT_NULL)
309ebfedea0SLionel Sambuc 	mach_port_deallocate(mach_task_self(), ipc->server);
310ebfedea0SLionel Sambuc     free(ipc->name);
311ebfedea0SLionel Sambuc     free(ipc);
312ebfedea0SLionel Sambuc     return 0;
313ebfedea0SLionel Sambuc }
314ebfedea0SLionel Sambuc 
315ebfedea0SLionel Sambuc #endif
316ebfedea0SLionel Sambuc 
317ebfedea0SLionel Sambuc struct path_ctx {
318ebfedea0SLionel Sambuc     char *path;
319ebfedea0SLionel Sambuc     int fd;
320ebfedea0SLionel Sambuc };
321ebfedea0SLionel Sambuc 
322ebfedea0SLionel Sambuc static int common_release(void *);
323ebfedea0SLionel Sambuc 
324ebfedea0SLionel Sambuc static int
connect_unix(struct path_ctx * s)325ebfedea0SLionel Sambuc connect_unix(struct path_ctx *s)
326ebfedea0SLionel Sambuc {
327ebfedea0SLionel Sambuc     struct sockaddr_un addr;
328ebfedea0SLionel Sambuc 
329ebfedea0SLionel Sambuc     addr.sun_family = AF_UNIX;
330ebfedea0SLionel Sambuc     strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path));
331ebfedea0SLionel Sambuc 
332ebfedea0SLionel Sambuc     s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
333ebfedea0SLionel Sambuc     if (s->fd < 0)
334ebfedea0SLionel Sambuc 	return errno;
335ebfedea0SLionel Sambuc     rk_cloexec(s->fd);
336ebfedea0SLionel Sambuc 
337ebfedea0SLionel Sambuc     if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
338ebfedea0SLionel Sambuc 	close(s->fd);
339ebfedea0SLionel Sambuc 	return errno;
340ebfedea0SLionel Sambuc     }
341ebfedea0SLionel Sambuc 
342ebfedea0SLionel Sambuc     return 0;
343ebfedea0SLionel Sambuc }
344ebfedea0SLionel Sambuc 
345ebfedea0SLionel Sambuc static int
common_path_init(const char * service,const char * file,void ** ctx)346ebfedea0SLionel Sambuc common_path_init(const char *service,
347ebfedea0SLionel Sambuc 		 const char *file,
348ebfedea0SLionel Sambuc 		 void **ctx)
349ebfedea0SLionel Sambuc {
350ebfedea0SLionel Sambuc     struct path_ctx *s;
351ebfedea0SLionel Sambuc 
352ebfedea0SLionel Sambuc     s = malloc(sizeof(*s));
353ebfedea0SLionel Sambuc     if (s == NULL)
354ebfedea0SLionel Sambuc 	return ENOMEM;
355ebfedea0SLionel Sambuc     s->fd = -1;
356ebfedea0SLionel Sambuc 
357ebfedea0SLionel Sambuc     asprintf(&s->path, "/var/run/.heim_%s-%s", service, file);
358ebfedea0SLionel Sambuc 
359ebfedea0SLionel Sambuc     *ctx = s;
360ebfedea0SLionel Sambuc 
361ebfedea0SLionel Sambuc     return 0;
362ebfedea0SLionel Sambuc }
363ebfedea0SLionel Sambuc 
364ebfedea0SLionel Sambuc static int
unix_socket_init(const char * service,void ** ctx)365ebfedea0SLionel Sambuc unix_socket_init(const char *service,
366ebfedea0SLionel Sambuc 		 void **ctx)
367ebfedea0SLionel Sambuc {
368ebfedea0SLionel Sambuc     int ret;
369ebfedea0SLionel Sambuc 
370ebfedea0SLionel Sambuc     ret = common_path_init(service, "socket", ctx);
371ebfedea0SLionel Sambuc     if (ret)
372ebfedea0SLionel Sambuc 	return ret;
373ebfedea0SLionel Sambuc     ret = connect_unix(*ctx);
374ebfedea0SLionel Sambuc     if (ret)
375ebfedea0SLionel Sambuc 	common_release(*ctx);
376ebfedea0SLionel Sambuc 
377ebfedea0SLionel Sambuc     return ret;
378ebfedea0SLionel Sambuc }
379ebfedea0SLionel Sambuc 
380ebfedea0SLionel Sambuc static int
unix_socket_ipc(void * ctx,const heim_idata * req,heim_idata * rep,heim_icred * cred)381ebfedea0SLionel Sambuc unix_socket_ipc(void *ctx,
382ebfedea0SLionel Sambuc 		const heim_idata *req, heim_idata *rep,
383ebfedea0SLionel Sambuc 		heim_icred *cred)
384ebfedea0SLionel Sambuc {
385ebfedea0SLionel Sambuc     struct path_ctx *s = ctx;
386ebfedea0SLionel Sambuc     uint32_t len = htonl(req->length);
387ebfedea0SLionel Sambuc     uint32_t rv;
388ebfedea0SLionel Sambuc     int retval;
389ebfedea0SLionel Sambuc 
390ebfedea0SLionel Sambuc     if (cred)
391ebfedea0SLionel Sambuc 	*cred = NULL;
392ebfedea0SLionel Sambuc 
393ebfedea0SLionel Sambuc     rep->data = NULL;
394ebfedea0SLionel Sambuc     rep->length = 0;
395ebfedea0SLionel Sambuc 
396ebfedea0SLionel Sambuc     if (net_write(s->fd, &len, sizeof(len)) != sizeof(len))
397ebfedea0SLionel Sambuc 	return -1;
398*0a6a1f1dSLionel Sambuc     if (net_write(s->fd, req->data, req->length) != (ssize_t)req->length)
399ebfedea0SLionel Sambuc 	return -1;
400ebfedea0SLionel Sambuc 
401ebfedea0SLionel Sambuc     if (net_read(s->fd, &len, sizeof(len)) != sizeof(len))
402ebfedea0SLionel Sambuc 	return -1;
403ebfedea0SLionel Sambuc     if (net_read(s->fd, &rv, sizeof(rv)) != sizeof(rv))
404ebfedea0SLionel Sambuc 	return -1;
405ebfedea0SLionel Sambuc     retval = ntohl(rv);
406ebfedea0SLionel Sambuc 
407ebfedea0SLionel Sambuc     rep->length = ntohl(len);
408ebfedea0SLionel Sambuc     if (rep->length > 0) {
409ebfedea0SLionel Sambuc 	rep->data = malloc(rep->length);
410ebfedea0SLionel Sambuc 	if (rep->data == NULL)
411ebfedea0SLionel Sambuc 	    return -1;
412*0a6a1f1dSLionel Sambuc 	if (net_read(s->fd, rep->data, rep->length) != (ssize_t)rep->length)
413ebfedea0SLionel Sambuc 	    return -1;
414ebfedea0SLionel Sambuc     } else
415ebfedea0SLionel Sambuc 	rep->data = NULL;
416ebfedea0SLionel Sambuc 
417ebfedea0SLionel Sambuc     return retval;
418ebfedea0SLionel Sambuc }
419ebfedea0SLionel Sambuc 
420ebfedea0SLionel Sambuc int
common_release(void * ctx)421ebfedea0SLionel Sambuc common_release(void *ctx)
422ebfedea0SLionel Sambuc {
423ebfedea0SLionel Sambuc     struct path_ctx *s = ctx;
424ebfedea0SLionel Sambuc     if (s->fd >= 0)
425ebfedea0SLionel Sambuc 	close(s->fd);
426ebfedea0SLionel Sambuc     free(s->path);
427ebfedea0SLionel Sambuc     free(s);
428ebfedea0SLionel Sambuc     return 0;
429ebfedea0SLionel Sambuc }
430ebfedea0SLionel Sambuc 
431ebfedea0SLionel Sambuc #ifdef HAVE_DOOR
432ebfedea0SLionel Sambuc 
433ebfedea0SLionel Sambuc static int
door_init(const char * service,void ** ctx)434ebfedea0SLionel Sambuc door_init(const char *service,
435ebfedea0SLionel Sambuc 	  void **ctx)
436ebfedea0SLionel Sambuc {
437ebfedea0SLionel Sambuc     ret = common_path_init(context, service, "door", ctx);
438ebfedea0SLionel Sambuc     if (ret)
439ebfedea0SLionel Sambuc 	return ret;
440ebfedea0SLionel Sambuc     ret = connect_door(*ctx);
441ebfedea0SLionel Sambuc     if (ret)
442ebfedea0SLionel Sambuc 	common_release(*ctx);
443ebfedea0SLionel Sambuc     return ret;
444ebfedea0SLionel Sambuc }
445ebfedea0SLionel Sambuc 
446ebfedea0SLionel Sambuc static int
door_ipc(void * ctx,const heim_idata * request,heim_idata * response,heim_icred * cred)447ebfedea0SLionel Sambuc door_ipc(void *ctx,
448ebfedea0SLionel Sambuc 	 const heim_idata *request, heim_idata *response,
449ebfedea0SLionel Sambuc 	 heim_icred *cred)
450ebfedea0SLionel Sambuc {
451ebfedea0SLionel Sambuc     door_arg_t arg;
452ebfedea0SLionel Sambuc     int ret;
453ebfedea0SLionel Sambuc 
454ebfedea0SLionel Sambuc     arg.data_ptr = request->data;
455ebfedea0SLionel Sambuc     arg.data_size = request->length;
456ebfedea0SLionel Sambuc     arg.desc_ptr = NULL;
457ebfedea0SLionel Sambuc     arg.desc_num = 0;
458ebfedea0SLionel Sambuc     arg.rbuf = NULL;
459ebfedea0SLionel Sambuc     arg.rsize = 0;
460ebfedea0SLionel Sambuc 
461ebfedea0SLionel Sambuc     ret = door_call(fd, &arg);
462ebfedea0SLionel Sambuc     close(fd);
463ebfedea0SLionel Sambuc     if (ret != 0)
464ebfedea0SLionel Sambuc 	return errno;
465ebfedea0SLionel Sambuc 
466ebfedea0SLionel Sambuc     response->data = malloc(arg.rsize);
467ebfedea0SLionel Sambuc     if (response->data == NULL) {
468ebfedea0SLionel Sambuc 	munmap(arg.rbuf, arg.rsize);
469ebfedea0SLionel Sambuc 	return ENOMEM;
470ebfedea0SLionel Sambuc     }
471ebfedea0SLionel Sambuc     memcpy(response->data, arg.rbuf, arg.rsize);
472ebfedea0SLionel Sambuc     response->length = arg.rsize;
473ebfedea0SLionel Sambuc     munmap(arg.rbuf, arg.rsize);
474ebfedea0SLionel Sambuc 
475ebfedea0SLionel Sambuc     return ret;
476ebfedea0SLionel Sambuc }
477ebfedea0SLionel Sambuc 
478ebfedea0SLionel Sambuc #endif
479ebfedea0SLionel Sambuc 
480ebfedea0SLionel Sambuc struct hipc_ops {
481ebfedea0SLionel Sambuc     const char *prefix;
482ebfedea0SLionel Sambuc     int (*init)(const char *, void **);
483ebfedea0SLionel Sambuc     int (*release)(void *);
484ebfedea0SLionel Sambuc     int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *);
485ebfedea0SLionel Sambuc     int (*async)(void *, const heim_idata *, void *,
486ebfedea0SLionel Sambuc 		 void (*)(void *, int, heim_idata *, heim_icred));
487ebfedea0SLionel Sambuc };
488ebfedea0SLionel Sambuc 
489ebfedea0SLionel Sambuc struct hipc_ops ipcs[] = {
490ebfedea0SLionel Sambuc #if defined(__APPLE__) && defined(HAVE_GCD)
491ebfedea0SLionel Sambuc     { "MACH", mach_init, mach_release, mach_ipc, mach_async },
492ebfedea0SLionel Sambuc #endif
493ebfedea0SLionel Sambuc #ifdef HAVE_DOOR
494*0a6a1f1dSLionel Sambuc     { "DOOR", door_init, common_release, door_ipc, NULL }
495ebfedea0SLionel Sambuc #endif
496*0a6a1f1dSLionel Sambuc     { "UNIX", unix_socket_init, common_release, unix_socket_ipc, NULL }
497ebfedea0SLionel Sambuc };
498ebfedea0SLionel Sambuc 
499ebfedea0SLionel Sambuc struct heim_ipc {
500ebfedea0SLionel Sambuc     struct hipc_ops *ops;
501ebfedea0SLionel Sambuc     void *ctx;
502ebfedea0SLionel Sambuc };
503ebfedea0SLionel Sambuc 
504ebfedea0SLionel Sambuc 
505ebfedea0SLionel Sambuc int
heim_ipc_init_context(const char * name,heim_ipc * ctx)506ebfedea0SLionel Sambuc heim_ipc_init_context(const char *name, heim_ipc *ctx)
507ebfedea0SLionel Sambuc {
508ebfedea0SLionel Sambuc     unsigned int i;
509ebfedea0SLionel Sambuc     int ret, any = 0;
510ebfedea0SLionel Sambuc 
511ebfedea0SLionel Sambuc     for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) {
512ebfedea0SLionel Sambuc 	size_t prefix_len = strlen(ipcs[i].prefix);
513ebfedea0SLionel Sambuc 	heim_ipc c;
514ebfedea0SLionel Sambuc 	if(strncmp(ipcs[i].prefix, name, prefix_len) == 0
515ebfedea0SLionel Sambuc 	   && name[prefix_len] == ':')  {
516ebfedea0SLionel Sambuc 	} else if (strncmp("ANY:", name, 4) == 0) {
517ebfedea0SLionel Sambuc 	    prefix_len = 3;
518ebfedea0SLionel Sambuc 	    any = 1;
519ebfedea0SLionel Sambuc 	} else
520ebfedea0SLionel Sambuc 	    continue;
521ebfedea0SLionel Sambuc 
522ebfedea0SLionel Sambuc 	c = calloc(1, sizeof(*c));
523ebfedea0SLionel Sambuc 	if (c == NULL)
524ebfedea0SLionel Sambuc 	    return ENOMEM;
525ebfedea0SLionel Sambuc 
526ebfedea0SLionel Sambuc 	c->ops = &ipcs[i];
527ebfedea0SLionel Sambuc 
528ebfedea0SLionel Sambuc 	ret = (c->ops->init)(name + prefix_len + 1, &c->ctx);
529ebfedea0SLionel Sambuc 	if (ret) {
530ebfedea0SLionel Sambuc 	    free(c);
531ebfedea0SLionel Sambuc 	    if (any)
532ebfedea0SLionel Sambuc 		continue;
533ebfedea0SLionel Sambuc 	    return ret;
534ebfedea0SLionel Sambuc 	}
535ebfedea0SLionel Sambuc 
536ebfedea0SLionel Sambuc 	*ctx = c;
537ebfedea0SLionel Sambuc 	return 0;
538ebfedea0SLionel Sambuc     }
539ebfedea0SLionel Sambuc 
540ebfedea0SLionel Sambuc     return ENOENT;
541ebfedea0SLionel Sambuc }
542ebfedea0SLionel Sambuc 
543ebfedea0SLionel Sambuc void
heim_ipc_free_context(heim_ipc ctx)544ebfedea0SLionel Sambuc heim_ipc_free_context(heim_ipc ctx)
545ebfedea0SLionel Sambuc {
546ebfedea0SLionel Sambuc     (ctx->ops->release)(ctx->ctx);
547ebfedea0SLionel Sambuc     free(ctx);
548ebfedea0SLionel Sambuc }
549ebfedea0SLionel Sambuc 
550ebfedea0SLionel Sambuc int
heim_ipc_call(heim_ipc ctx,const heim_idata * snd,heim_idata * rcv,heim_icred * cred)551*0a6a1f1dSLionel Sambuc heim_ipc_call(heim_ipc ctx, const heim_idata *snd, heim_idata *rcv,
552ebfedea0SLionel Sambuc 	      heim_icred *cred)
553ebfedea0SLionel Sambuc {
554ebfedea0SLionel Sambuc     if (cred)
555ebfedea0SLionel Sambuc 	*cred = NULL;
556*0a6a1f1dSLionel Sambuc     return (ctx->ops->ipc)(ctx->ctx, snd, rcv, cred);
557ebfedea0SLionel Sambuc }
558ebfedea0SLionel Sambuc 
559ebfedea0SLionel Sambuc int
heim_ipc_async(heim_ipc ctx,const heim_idata * snd,void * userctx,void (* func)(void *,int,heim_idata *,heim_icred))560*0a6a1f1dSLionel Sambuc heim_ipc_async(heim_ipc ctx, const heim_idata *snd, void *userctx,
561ebfedea0SLionel Sambuc 	       void (*func)(void *, int, heim_idata *, heim_icred))
562ebfedea0SLionel Sambuc {
563ebfedea0SLionel Sambuc     if (ctx->ops->async == NULL) {
564*0a6a1f1dSLionel Sambuc 	heim_idata rcv;
565ebfedea0SLionel Sambuc 	heim_icred cred = NULL;
566ebfedea0SLionel Sambuc 	int ret;
567ebfedea0SLionel Sambuc 
568*0a6a1f1dSLionel Sambuc 	ret = (ctx->ops->ipc)(ctx->ctx, snd, &rcv, &cred);
569*0a6a1f1dSLionel Sambuc 	(*func)(userctx, ret, &rcv, cred);
570ebfedea0SLionel Sambuc 	heim_ipc_free_cred(cred);
571*0a6a1f1dSLionel Sambuc 	free(rcv.data);
572ebfedea0SLionel Sambuc 	return ret;
573ebfedea0SLionel Sambuc     } else {
574*0a6a1f1dSLionel Sambuc 	return (ctx->ops->async)(ctx->ctx, snd, userctx, func);
575ebfedea0SLionel Sambuc     }
576ebfedea0SLionel Sambuc }
577