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