summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/ipc')
-rw-r--r--third_party/heimdal/lib/ipc/Makefile.am76
-rw-r--r--third_party/heimdal/lib/ipc/client.c610
-rw-r--r--third_party/heimdal/lib/ipc/common.c206
-rw-r--r--third_party/heimdal/lib/ipc/heim-ipc.h133
-rw-r--r--third_party/heimdal/lib/ipc/heim_ipc.defs66
-rw-r--r--third_party/heimdal/lib/ipc/heim_ipc_async.defs56
-rw-r--r--third_party/heimdal/lib/ipc/heim_ipc_reply.defs51
-rw-r--r--third_party/heimdal/lib/ipc/heim_ipc_types.h44
-rw-r--r--third_party/heimdal/lib/ipc/hi_locl.h83
-rw-r--r--third_party/heimdal/lib/ipc/server.c1372
-rw-r--r--third_party/heimdal/lib/ipc/tc.c138
-rw-r--r--third_party/heimdal/lib/ipc/ts-http.c136
-rw-r--r--third_party/heimdal/lib/ipc/ts.c116
13 files changed, 3087 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/ipc/Makefile.am b/third_party/heimdal/lib/ipc/Makefile.am
new file mode 100644
index 0000000..04ff213
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/Makefile.am
@@ -0,0 +1,76 @@
+include $(top_srcdir)/Makefile.am.common
+
+noinst_LTLIBRARIES = libheim-ipcc.la libheim-ipcs.la
+
+dist_libheim_ipcc_la_SOURCES = hi_locl.h heim_ipc_types.h client.c common.c
+dist_libheim_ipcs_la_SOURCES = hi_locl.h heim_ipc_types.h server.c common.c
+
+include_HEADERS = heim-ipc.h
+
+##
+## Enable when this is not a noinst_ library
+##
+#libheim_ipcc_la_LDFLAGS = -version-info 0:0:0
+#libheim_ipcs_la_LDFLAGS = -version-info 0:0:0
+#
+#if versionscript
+#libheim_ipcc_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scriptc.map
+#libheim_ipcs_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scripts.map
+#endif
+
+libheim_ipcc_la_LIBADD = \
+ $(LIB_heimbase) \
+ $(LIB_roken) \
+ $(PTHREAD_LIBADD)
+
+if SUNOS
+libheim_ipcc_la_LIBADD += -lsocket
+endif
+
+libheim_ipcs_la_LIBADD = $(libheim_ipcc_la_LIBADD)
+
+TESTS = $(check_PROGRAMS)
+
+noinst_PROGRAMS = tc ts ts-http
+
+ts_LDADD = libheim-ipcs.la $(LIB_roken)
+ts_http_LDADD = $(ts_LDADD)
+tc_LDADD = libheim-ipcc.la $(LIB_roken)
+
+
+EXTRA_DIST = heim_ipc.defs heim_ipc_async.defs heim_ipc_reply.defs
+
+if have_gcd
+
+# We still use dispatch_get_current_queue(), which is deprecated, and that
+# stops building on recent OS X releases unless we disable this warning.
+WFLAGS += -Wno-deprecated-declarations
+
+heim_ipc.h heim_ipcUser.c heim_ipcServer.c heim_ipcServer.h: heim_ipc.defs
+ mig -header heim_ipc.h -user heim_ipcUser.c -sheader heim_ipcServer.h -server heim_ipcServer.c -I$(srcdir) $(srcdir)/heim_ipc.defs
+
+heim_ipc_async.h heim_ipc_asyncUser.c heim_ipc_asyncServer.c heim_ipc_asyncServer.h: heim_ipc_async.defs
+ mig -header heim_ipc_async.h -user heim_ipc_asyncUser.c -sheader heim_ipc_asyncServer.h -server heim_ipc_asyncServer.c -I$(srcdir) $(srcdir)/heim_ipc_async.defs
+
+heim_ipc_reply.h heim_ipc_replyUser.c: heim_ipc_reply.defs
+ mig -header heim_ipc_reply.h -user heim_ipc_replyUser.c -sheader /dev/null -server /dev/null -I$(srcdir) $(srcdir)/heim_ipc_reply.defs
+
+built_ipcc = heim_ipc.h heim_ipcUser.c
+built_ipcc += heim_ipc_asyncServer.c heim_ipc_asyncServer.h
+
+nodist_libheim_ipcc_la_SOURCES = $(built_ipcc)
+
+built_ipcs = heim_ipcServer.c heim_ipcServer.h
+built_ipcs += heim_ipc_asyncUser.c heim_ipc_async.h
+built_ipcs += heim_ipc_reply.h heim_ipc_replyUser.c
+
+nodist_libheim_ipcs_la_SOURCES = $(built_ipcs)
+
+libheim_ipcs_la_LIBADD += -lbsm
+
+CLEANFILES = $(built_ipcc) $(built_ipcs)
+
+$(srcdir)/client.c: $(built_ipcc)
+$(srcdir)/server.c: $(built_ipcs)
+
+endif
diff --git a/third_party/heimdal/lib/ipc/client.c b/third_party/heimdal/lib/ipc/client.c
new file mode 100644
index 0000000..d4d3c03
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/client.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hi_locl.h"
+
+#if defined(__APPLE__) && defined(HAVE_GCD)
+
+#include "heim_ipc.h"
+#include "heim_ipc_asyncServer.h"
+
+#include <dispatch/dispatch.h>
+#include <mach/mach.h>
+
+static dispatch_once_t jobqinited = 0;
+static dispatch_queue_t jobq = NULL;
+static dispatch_queue_t syncq;
+
+struct mach_ctx {
+ mach_port_t server;
+ char *name;
+};
+
+static int
+mach_release(void *ctx);
+
+static int
+mach_init(const char *service, void **ctx)
+{
+ struct mach_ctx *ipc;
+ mach_port_t sport;
+ int ret;
+
+ dispatch_once(&jobqinited, ^{
+ jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ syncq = dispatch_queue_create("heim-ipc-syncq", NULL);
+ });
+
+ ret = bootstrap_look_up(bootstrap_port, service, &sport);
+ if (ret)
+ return ret;
+
+ ipc = malloc(sizeof(*ipc));
+ if (ipc == NULL) {
+ mach_port_destroy(mach_task_self(), sport);
+ return ENOMEM;
+ }
+
+ ipc->server = sport;
+ ipc->name = strdup(service);
+ if (ipc->name == NULL) {
+ mach_release(ipc);
+ return ENOMEM;
+ }
+
+ *ctx = ipc;
+
+ return 0;
+}
+
+static int
+mach_ipc(void *ctx,
+ const heim_idata *request, heim_idata *response,
+ heim_icred *cred)
+{
+ struct mach_ctx *ipc = ctx;
+ heim_ipc_message_inband_t requestin;
+ mach_msg_type_number_t requestin_length = 0;
+ heim_ipc_message_outband_t requestout = NULL;
+ mach_msg_type_number_t requestout_length = 0;
+ heim_ipc_message_inband_t replyin;
+ mach_msg_type_number_t replyin_length;
+ heim_ipc_message_outband_t replyout;
+ mach_msg_type_number_t replyout_length;
+ int ret, errorcode, retries = 0;
+
+ memcpy(requestin, request->data, request->length);
+ requestin_length = request->length;
+
+ while (retries < 2) {
+ __block mach_port_t sport;
+
+ dispatch_sync(syncq, ^{ sport = ipc->server; });
+
+ ret = mheim_ipc_call(sport,
+ requestin, requestin_length,
+ requestout, requestout_length,
+ &errorcode,
+ replyin, &replyin_length,
+ &replyout, &replyout_length);
+ if (ret == MACH_SEND_INVALID_DEST) {
+ mach_port_t nport;
+ /* race other threads to get a new port */
+ ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport);
+ if (ret)
+ return ret;
+ dispatch_sync(syncq, ^{
+ /* check if we lost the race to lookup the port */
+ if (sport != ipc->server) {
+ mach_port_deallocate(mach_task_self(), nport);
+ } else {
+ mach_port_deallocate(mach_task_self(), ipc->server);
+ ipc->server = nport;
+ }
+ });
+ retries++;
+ } else if (ret) {
+ return ret;
+ } else
+ break;
+ }
+ if (retries >= 2)
+ return EINVAL;
+
+ if (errorcode) {
+ if (replyout_length)
+ vm_deallocate (mach_task_self (), (vm_address_t) replyout,
+ replyout_length);
+ return errorcode;
+ }
+
+ if (replyout_length) {
+ response->data = malloc(replyout_length);
+ if (response->data == NULL) {
+ vm_deallocate (mach_task_self (), (vm_address_t) replyout,
+ replyout_length);
+ return ENOMEM;
+ }
+ memcpy(response->data, replyout, replyout_length);
+ response->length = replyout_length;
+ vm_deallocate (mach_task_self (), (vm_address_t) replyout,
+ replyout_length);
+ } else {
+ response->data = malloc(replyin_length);
+ if (response->data == NULL)
+ return ENOMEM;
+ memcpy(response->data, replyin, replyin_length);
+ response->length = replyin_length;
+ }
+
+ return 0;
+}
+
+struct async_client {
+ mach_port_t mp;
+ dispatch_source_t source;
+ dispatch_queue_t queue;
+ void (*func)(void *, int, heim_idata *, heim_icred);
+ void *userctx;
+};
+
+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)
+{
+ struct async_client *c = dispatch_get_context(dispatch_get_current_queue());
+ heim_idata response;
+
+ if (returnvalue) {
+ response.data = NULL;
+ response.length = 0;
+ } else if (replyoutCnt) {
+ response.data = replyout;
+ response.length = replyoutCnt;
+ } else {
+ response.data = replyin;
+ response.length = replyinCnt;
+ }
+
+ (*c->func)(c->userctx, returnvalue, &response, NULL);
+
+ if (replyoutCnt)
+ vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt);
+
+ dispatch_source_cancel(c->source);
+
+ return 0;
+
+
+}
+
+
+static int
+mach_async(void *ctx, const heim_idata *request, void *userctx,
+ void (*func)(void *, int, heim_idata *, heim_icred))
+{
+ struct mach_ctx *ipc = ctx;
+ heim_ipc_message_inband_t requestin;
+ mach_msg_type_number_t requestin_length = 0;
+ heim_ipc_message_outband_t requestout = NULL;
+ mach_msg_type_number_t requestout_length = 0;
+ int ret, retries = 0;
+ kern_return_t kr;
+ struct async_client *c;
+
+ /* first create the service that will catch the reply from the server */
+ /* XXX these object should be cached and reused */
+
+ c = malloc(sizeof(*c));
+ if (c == NULL)
+ return ENOMEM;
+
+ kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp);
+ if (kr != KERN_SUCCESS)
+ return EINVAL;
+
+ c->queue = dispatch_queue_create("heim-ipc-async-client", NULL);
+ c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue);
+ dispatch_set_context(c->queue, c);
+
+ dispatch_source_set_event_handler(c->source, ^{
+ dispatch_mig_server(c->source,
+ sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem),
+ mheim_aipc_server);
+ });
+
+ dispatch_source_set_cancel_handler(c->source, ^{
+ mach_port_mod_refs(mach_task_self(), c->mp,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ dispatch_release(c->queue);
+ dispatch_release(c->source);
+ free(c);
+ });
+
+ c->func = func;
+ c->userctx = userctx;
+
+ dispatch_resume(c->source);
+
+ /* ok, send the message */
+
+ memcpy(requestin, request->data, request->length);
+ requestin_length = request->length;
+
+ while (retries < 2) {
+ __block mach_port_t sport;
+
+ dispatch_sync(syncq, ^{ sport = ipc->server; });
+
+ ret = mheim_ipc_call_request(sport, c->mp,
+ requestin, requestin_length,
+ requestout, requestout_length);
+ if (ret == MACH_SEND_INVALID_DEST) {
+ ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport);
+ if (ret) {
+ dispatch_source_cancel(c->source);
+ return ret;
+ }
+ mach_port_deallocate(mach_task_self(), ipc->server);
+ ipc->server = sport;
+ retries++;
+ } else if (ret) {
+ dispatch_source_cancel(c->source);
+ return ret;
+ } else
+ break;
+ }
+ if (retries >= 2) {
+ dispatch_source_cancel(c->source);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+mach_release(void *ctx)
+{
+ struct mach_ctx *ipc = ctx;
+ if (ipc->server != MACH_PORT_NULL)
+ mach_port_deallocate(mach_task_self(), ipc->server);
+ free(ipc->name);
+ free(ipc);
+ return 0;
+}
+
+#endif
+
+struct path_ctx {
+ char *path;
+ int fd;
+};
+
+static int common_release(void *);
+
+static int
+connect_unix(struct path_ctx *s)
+{
+ struct sockaddr_un addr;
+
+ addr.sun_family = AF_UNIX;
+ strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path));
+
+ s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s->fd < 0)
+ return errno;
+ rk_cloexec(s->fd);
+
+ if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+ return errno;
+
+ return 0;
+}
+
+static int
+common_path_init(const char *base,
+ const char *service,
+ const char *file,
+ void **ctx)
+{
+ struct path_ctx *s;
+
+ s = malloc(sizeof(*s));
+ if (s == NULL)
+ return ENOMEM;
+ s->fd = -1;
+
+ if (asprintf(&s->path, "%s/.heim_%s-%s", base, service, file) == -1) {
+ free(s);
+ return ENOMEM;
+ }
+
+ *ctx = s;
+ return 0;
+}
+
+static int
+unix_socket_init(const char *service,
+ void **ctx)
+{
+ const char *base = secure_getenv("HEIM_IPC_DIR");
+ int ret;
+
+ ret = common_path_init(base ? base : _PATH_VARRUN, service, "socket", ctx);
+ if (ret)
+ return ret;
+ ret = connect_unix(*ctx);
+ if (ret)
+ common_release(*ctx);
+
+ return ret;
+}
+
+static int
+unix_socket_ipc(void *ctx,
+ const heim_idata *req, heim_idata *rep,
+ heim_icred *cred)
+{
+ struct path_ctx *s = ctx;
+ uint32_t len = htonl(req->length);
+ uint32_t rv;
+ int retval;
+
+ if (cred)
+ *cred = NULL;
+
+ rep->data = NULL;
+ rep->length = 0;
+
+ if (net_write(s->fd, &len, sizeof(len)) != sizeof(len))
+ return -1;
+ if (net_write(s->fd, req->data, req->length) != (ssize_t)req->length)
+ return -1;
+
+ if (net_read(s->fd, &len, sizeof(len)) != sizeof(len))
+ return -1;
+ if (net_read(s->fd, &rv, sizeof(rv)) != sizeof(rv))
+ return -1;
+ retval = ntohl(rv);
+
+ rep->length = ntohl(len);
+ if (rep->length > 0) {
+ rep->data = malloc(rep->length);
+ if (rep->data == NULL)
+ return -1;
+ if (net_read(s->fd, rep->data, rep->length) != (ssize_t)rep->length)
+ return -1;
+ } else
+ rep->data = NULL;
+
+ return retval;
+}
+
+int
+common_release(void *ctx)
+{
+ struct path_ctx *s = ctx;
+ if (s->fd >= 0)
+ close(s->fd);
+ free(s->path);
+ free(s);
+ return 0;
+}
+
+#ifdef HAVE_DOOR_CREATE
+
+#include <door.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+static int
+door_init(const char *service,
+ void **ctx)
+{
+ const char *base = secure_getenv("HEIM_IPC_DIR");
+ int ret;
+ struct path_ctx *d;
+
+ ret = common_path_init(base ? base : _PATH_VARRUN, service, "door", ctx);
+ if (ret)
+ return ret;
+
+ d = (struct path_ctx *)*ctx;
+ d->fd = open(d->path, O_RDWR);
+ if (d->fd < 0) {
+ ret = errno;
+ common_release(*ctx);
+ return ret;
+ }
+
+ return 0;
+}
+
+struct door_reply {
+ int returnvalue;
+ size_t length;
+ unsigned char data[1];
+};
+
+static int
+door_ipc(void *ctx,
+ const heim_idata *request, heim_idata *response,
+ heim_icred *cred)
+{
+ struct path_ctx *d = (struct path_ctx *)ctx;
+ door_arg_t arg;
+ int ret;
+ struct door_reply *r;
+
+ arg.data_ptr = request->data;
+ arg.data_size = request->length;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = NULL;
+ arg.rsize = 0;
+
+ ret = door_call(d->fd, &arg);
+ if (ret != 0)
+ return errno;
+
+ if (arg.rsize < offsetof(struct door_reply, data))
+ return EINVAL;
+
+ r = (struct door_reply *)arg.rbuf;
+ if (r->returnvalue != 0)
+ return r->returnvalue;
+
+ if (arg.rsize < offsetof(struct door_reply, data) + r->length)
+ return ERANGE;
+
+ response->data = malloc(r->length);
+ if (response->data == NULL) {
+ munmap(arg.rbuf, arg.rsize);
+ return ENOMEM;
+ }
+
+ memcpy(response->data, r->data, r->length);
+ response->length = r->length;
+ munmap(arg.rbuf, arg.rsize);
+
+ return 0;
+}
+
+#endif /* HAVE_DOOR_CREATE */
+
+struct hipc_ops {
+ const char *prefix;
+ int (*init)(const char *, void **);
+ int (*release)(void *);
+ int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *);
+ int (*async)(void *, const heim_idata *, void *,
+ void (*)(void *, int, heim_idata *, heim_icred));
+};
+
+static const struct hipc_ops ipcs[] = {
+#if defined(__APPLE__) && defined(HAVE_GCD)
+ { "MACH", mach_init, mach_release, mach_ipc, mach_async },
+#endif
+#ifdef HAVE_DOOR_CREATE
+ { "DOOR", door_init, common_release, door_ipc, NULL },
+#endif
+ { "UNIX", unix_socket_init, common_release, unix_socket_ipc, NULL }
+};
+
+struct heim_ipc {
+ const struct hipc_ops *ops;
+ void *ctx;
+};
+
+
+int
+heim_ipc_init_context(const char *name, heim_ipc *ctx)
+{
+ unsigned int i;
+ int ret, any = 0;
+
+ for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) {
+ size_t prefix_len = strlen(ipcs[i].prefix);
+ heim_ipc c;
+ if(strncmp(ipcs[i].prefix, name, prefix_len) == 0
+ && name[prefix_len] == ':') {
+ } else if (strncmp("ANY:", name, 4) == 0) {
+ prefix_len = 3;
+ any = 1;
+ } else
+ continue;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ return ENOMEM;
+
+ c->ops = &ipcs[i];
+
+ ret = (c->ops->init)(name + prefix_len + 1, &c->ctx);
+ if (ret) {
+ free(c);
+ if (any)
+ continue;
+ return ret;
+ }
+
+ *ctx = c;
+ return 0;
+ }
+
+ return ENOENT;
+}
+
+void
+heim_ipc_free_context(heim_ipc ctx)
+{
+ (ctx->ops->release)(ctx->ctx);
+ free(ctx);
+}
+
+int
+heim_ipc_call(heim_ipc ctx, const heim_idata *snd, heim_idata *rcv,
+ heim_icred *cred)
+{
+ if (cred)
+ *cred = NULL;
+ return (ctx->ops->ipc)(ctx->ctx, snd, rcv, cred);
+}
+
+int
+heim_ipc_async(heim_ipc ctx, const heim_idata *snd, void *userctx,
+ void (*func)(void *, int, heim_idata *, heim_icred))
+{
+ if (ctx->ops->async == NULL) {
+ heim_idata rcv;
+ heim_icred cred = NULL;
+ int ret;
+
+ ret = (ctx->ops->ipc)(ctx->ctx, snd, &rcv, &cred);
+ (*func)(userctx, ret, &rcv, cred);
+ heim_ipc_free_cred(cred);
+ free(rcv.data);
+ return ret;
+ } else {
+ return (ctx->ops->async)(ctx->ctx, snd, userctx, func);
+ }
+}
diff --git a/third_party/heimdal/lib/ipc/common.c b/third_party/heimdal/lib/ipc/common.c
new file mode 100644
index 0000000..cfbe4b5
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/common.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hi_locl.h"
+#ifdef HAVE_GCD
+#include <dispatch/dispatch.h>
+#else
+#include "heim_threads.h"
+#endif
+
+struct heim_icred {
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ pid_t session;
+};
+
+void
+heim_ipc_free_cred(heim_icred cred)
+{
+ free(cred);
+}
+
+uid_t
+heim_ipc_cred_get_uid(heim_icred cred)
+{
+ return cred ? cred->uid : (uid_t)-1;
+}
+
+gid_t
+heim_ipc_cred_get_gid(heim_icred cred)
+{
+ return cred ? cred->gid : (gid_t)-1;
+}
+
+pid_t
+heim_ipc_cred_get_pid(heim_icred cred)
+{
+ return cred ? cred->pid : (pid_t)0;
+}
+
+pid_t
+heim_ipc_cred_get_session(heim_icred cred)
+{
+ return cred ? cred->session : (pid_t)-1;
+}
+
+
+int
+_heim_ipc_create_cred(uid_t uid, gid_t gid, pid_t pid, pid_t session, heim_icred *cred)
+{
+ *cred = calloc(1, sizeof(**cred));
+ if (*cred == NULL)
+ return ENOMEM;
+ (*cred)->uid = uid;
+ (*cred)->gid = gid;
+ (*cred)->pid = pid;
+ (*cred)->session = session;
+ return 0;
+}
+
+#ifndef HAVE_GCD
+struct heim_isemaphore {
+ HEIMDAL_MUTEX mutex;
+#ifdef ENABLE_PTHREAD_SUPPORT
+ pthread_cond_t cond;
+#endif
+ long counter;
+};
+#endif
+
+heim_isemaphore
+heim_ipc_semaphore_create(long value)
+{
+#ifdef HAVE_GCD
+ return (heim_isemaphore)dispatch_semaphore_create(value);
+#elif !defined(ENABLE_PTHREAD_SUPPORT)
+ heim_assert(0, "no semaphore support w/o pthreads");
+ return NULL;
+#else
+ heim_isemaphore s = malloc(sizeof(*s));
+ if (s == NULL)
+ return NULL;
+ HEIMDAL_MUTEX_init(&s->mutex);
+ pthread_cond_init(&s->cond, NULL);
+ s->counter = value;
+ return s;
+#endif
+}
+
+long
+heim_ipc_semaphore_wait(heim_isemaphore s, time_t t)
+{
+#ifdef HAVE_GCD
+ uint64_t timeout;
+ if (t == HEIM_IPC_WAIT_FOREVER)
+ timeout = DISPATCH_TIME_FOREVER;
+ else
+ timeout = (uint64_t)t * NSEC_PER_SEC;
+
+ return dispatch_semaphore_wait((dispatch_semaphore_t)s, timeout);
+#elif !defined(ENABLE_PTHREAD_SUPPORT)
+ heim_assert(0, "no semaphore support w/o pthreads");
+ return 0;
+#else
+ HEIMDAL_MUTEX_lock(&s->mutex);
+ /* if counter hits below zero, we get to wait */
+ if (--s->counter < 0) {
+ int ret;
+
+ if (t == HEIM_IPC_WAIT_FOREVER)
+ ret = pthread_cond_wait(&s->cond, &s->mutex);
+ else {
+ struct timespec ts;
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+ ret = pthread_cond_timedwait(&s->cond, &s->mutex, &ts);
+ }
+ if (ret) {
+ HEIMDAL_MUTEX_unlock(&s->mutex);
+ return errno;
+ }
+ }
+ HEIMDAL_MUTEX_unlock(&s->mutex);
+
+ return 0;
+#endif
+}
+
+long
+heim_ipc_semaphore_signal(heim_isemaphore s)
+{
+#ifdef HAVE_GCD
+ return dispatch_semaphore_signal((dispatch_semaphore_t)s);
+#elif !defined(ENABLE_PTHREAD_SUPPORT)
+ heim_assert(0, "no semaphore support w/o pthreads");
+ return EINVAL;
+#else
+ int wakeup;
+ HEIMDAL_MUTEX_lock(&s->mutex);
+ wakeup = (++s->counter == 0) ;
+ HEIMDAL_MUTEX_unlock(&s->mutex);
+ if (wakeup)
+ pthread_cond_signal(&s->cond);
+ return 0;
+#endif
+}
+
+void
+heim_ipc_semaphore_release(heim_isemaphore s)
+{
+#ifdef HAVE_GCD
+ dispatch_release((dispatch_semaphore_t)s);
+#elif !defined(ENABLE_PTHREAD_SUPPORT)
+ heim_assert(0, "no semaphore support w/o pthreads");
+#else
+ HEIMDAL_MUTEX_lock(&s->mutex);
+ if (s->counter != 0)
+ abort();
+ HEIMDAL_MUTEX_unlock(&s->mutex);
+ HEIMDAL_MUTEX_destroy(&s->mutex);
+ pthread_cond_destroy(&s->cond);
+ free(s);
+#endif
+}
+
+void
+heim_ipc_free_data(heim_idata *data)
+{
+ if (data->data)
+ free(data->data);
+ data->data = NULL;
+ data->length = 0;
+}
diff --git a/third_party/heimdal/lib/ipc/heim-ipc.h b/third_party/heimdal/lib/ipc/heim-ipc.h
new file mode 100644
index 0000000..a34e338
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/heim-ipc.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <asn1-common.h>
+
+typedef struct heim_ipc *heim_ipc;
+typedef struct heim_sipc *heim_sipc;
+typedef struct heim_icred *heim_icred;
+typedef struct heim_isemaphore *heim_isemaphore;
+typedef struct heim_base_data heim_idata;
+typedef struct heim_sipc_call *heim_sipc_call;
+
+/* common */
+
+void
+heim_ipc_free_cred(heim_icred);
+
+uid_t
+heim_ipc_cred_get_uid(heim_icred);
+
+gid_t
+heim_ipc_cred_get_gid(heim_icred);
+
+pid_t
+heim_ipc_cred_get_pid(heim_icred);
+
+pid_t
+heim_ipc_cred_get_session(heim_icred);
+
+void
+heim_ipc_main(void);
+
+heim_isemaphore
+heim_ipc_semaphore_create(long);
+
+long
+heim_ipc_semaphore_wait(heim_isemaphore, time_t);
+
+long
+heim_ipc_semaphore_signal(heim_isemaphore);
+
+void
+heim_ipc_semaphore_release(heim_isemaphore);
+
+#define HEIM_IPC_WAIT_FOREVER ((time_t)-1)
+
+void
+heim_ipc_free_data(heim_idata *);
+
+/* client */
+
+int
+heim_ipc_init_context(const char *, heim_ipc *);
+
+void
+heim_ipc_free_context(heim_ipc);
+
+int
+heim_ipc_call(heim_ipc, const heim_idata *, heim_idata *, heim_icred *);
+
+int
+heim_ipc_async(heim_ipc, const heim_idata *, void *, void (*func)(void *, int, heim_idata *, heim_icred));
+
+/* server */
+
+#define HEIM_SIPC_TYPE_IPC 1
+#define HEIM_SIPC_TYPE_UINT32 2
+#define HEIM_SIPC_TYPE_HTTP 4
+
+typedef void
+(*heim_ipc_complete)(heim_sipc_call, int, heim_idata *);
+
+typedef void
+(*heim_ipc_callback)(void *, const heim_idata *,
+ const heim_icred, heim_ipc_complete, heim_sipc_call);
+
+
+int
+heim_sipc_launchd_mach_init(const char *, heim_ipc_callback,
+ void *, heim_sipc *);
+
+int
+heim_sipc_stream_listener(int, int, heim_ipc_callback,
+ void *, heim_sipc *);
+
+int
+heim_sipc_service_unix(const char *, heim_ipc_callback,
+ void *, heim_sipc *);
+
+int
+heim_sipc_service_door(const char *, heim_ipc_callback,
+ void *, heim_sipc *);
+
+void
+heim_sipc_timeout(time_t);
+
+void
+heim_sipc_set_timeout_handler(void (*)(void));
+
+void
+heim_sipc_free_context(heim_sipc);
diff --git a/third_party/heimdal/lib/ipc/heim_ipc.defs b/third_party/heimdal/lib/ipc/heim_ipc.defs
new file mode 100644
index 0000000..d2af7ec
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/heim_ipc.defs
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+type heim_ipc_message_inband_t = array [ * : 2048 ] of char;
+type heim_ipc_message_outband_t = array [] of char;
+
+import "heim_ipc_types.h";
+
+subsystem mheim_ipc 1;
+userprefix mheim_ipc_;
+serverprefix mheim_do_;
+
+routine call(
+ server_port : mach_port_t;
+ ServerAuditToken client_creds : audit_token_t;
+ sreplyport reply_port : mach_port_make_send_once_t;
+ in requestin : heim_ipc_message_inband_t;
+ in requestout : heim_ipc_message_outband_t;
+ out returnvalue : int;
+ out replyin : heim_ipc_message_inband_t;
+ out replyout : heim_ipc_message_outband_t, dealloc);
+
+simpleroutine call_request(
+ server_port : mach_port_t;
+ ServerAuditToken client_creds : audit_token_t;
+ in reply_to : mach_port_make_send_once_t;
+ in requestin : heim_ipc_message_inband_t;
+ in requestout : heim_ipc_message_outband_t);
+
+
+
diff --git a/third_party/heimdal/lib/ipc/heim_ipc_async.defs b/third_party/heimdal/lib/ipc/heim_ipc_async.defs
new file mode 100644
index 0000000..406e6a2
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/heim_ipc_async.defs
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+type heim_ipc_message_inband_t = array [ * : 2048 ] of char;
+type heim_ipc_message_outband_t = array [] of char;
+
+import "heim_ipc_types.h";
+
+subsystem mheim_aipc 201;
+userprefix mheim_aipc_;
+serverprefix mheim_ado_;
+
+simpleroutine acall_reply(
+ server_port : mach_port_move_send_once_t;
+ ServerAuditToken client_creds : audit_token_t;
+ in returnvalue : int;
+ in requestin : heim_ipc_message_inband_t;
+ in requestout : heim_ipc_message_outband_t);
+
+
+
diff --git a/third_party/heimdal/lib/ipc/heim_ipc_reply.defs b/third_party/heimdal/lib/ipc/heim_ipc_reply.defs
new file mode 100644
index 0000000..f95d0fa
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/heim_ipc_reply.defs
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+type heim_ipc_message_inband_t = array [ * : 2048 ] of char;
+type heim_ipc_message_outband_t = array [] of char;
+
+import "heim_ipc_types.h";
+
+subsystem heim_ipc 101;
+userprefix mheim_ripc_;
+
+simpleroutine call_reply(
+ reply_port : mach_port_move_send_once_t;
+ returnvalue : int;
+ replyin : heim_ipc_message_inband_t;
+ replyout : heim_ipc_message_outband_t, dealloc);
diff --git a/third_party/heimdal/lib/ipc/heim_ipc_types.h b/third_party/heimdal/lib/ipc/heim_ipc_types.h
new file mode 100644
index 0000000..fb5c165
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/heim_ipc_types.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _HEIM_IPC_TYPES_H_
+#define _HEIM_IPC_TYPES_H_
+
+#define HEIM_KCM_BOOTSTRAP_NAME "org.h5l.Kerberos.kcm"
+
+typedef char heim_ipc_message_inband_t[2048];
+typedef char *heim_ipc_message_outband_t;
+
+#endif
diff --git a/third_party/heimdal/lib/ipc/hi_locl.h b/third_party/heimdal/lib/ipc/hi_locl.h
new file mode 100644
index 0000000..6ec28ff
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/hi_locl.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#include <sys/poll.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_GETPEERUCRED
+#include <ucred.h>
+#endif
+
+#include <krb5-types.h>
+#include <asn1-common.h>
+
+#include <heimbase.h>
+#include <base64.h>
+
+#include <heim-ipc.h>
+
+#if defined(__APPLE__) && defined(HAVE_GCD)
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+#include <dispatch/dispatch.h>
+#include <bsm/libbsm.h>
+
+#ifndef __APPLE_PRIVATE__ /* awe, using private interface */
+typedef boolean_t (*dispatch_mig_callback_t)(mach_msg_header_t *message, mach_msg_header_t *reply);
+
+mach_msg_return_t
+dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, dispatch_mig_callback_t callback);
+#endif
+
+#endif
+
+
+#include <roken.h>
+
+int
+_heim_ipc_create_cred(uid_t, gid_t, pid_t, pid_t, heim_icred *);
diff --git a/third_party/heimdal/lib/ipc/server.c b/third_party/heimdal/lib/ipc/server.c
new file mode 100644
index 0000000..5ada75a
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/server.c
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "hi_locl.h"
+#include <assert.h>
+#include <err.h>
+
+#define MAX_PACKET_SIZE (128 * 1024)
+
+struct heim_sipc {
+ int (*release)(heim_sipc ctx);
+ heim_ipc_callback callback;
+ void *userctx;
+ void *mech;
+};
+
+#if defined(__APPLE__) && defined(HAVE_GCD)
+
+#include "heim_ipcServer.h"
+#include "heim_ipc_reply.h"
+#include "heim_ipc_async.h"
+
+static dispatch_source_t timer;
+static dispatch_queue_t timerq;
+static uint64_t timeoutvalue;
+
+static dispatch_queue_t eventq;
+
+static dispatch_queue_t workq;
+
+static void
+default_timer_ev(void)
+{
+ exit(0);
+}
+
+static void (*timer_ev)(void) = default_timer_ev;
+
+static void
+set_timer(void)
+{
+ dispatch_source_set_timer(timer,
+ dispatch_time(DISPATCH_TIME_NOW,
+ timeoutvalue * NSEC_PER_SEC),
+ timeoutvalue * NSEC_PER_SEC, 1000000);
+}
+
+static void
+init_globals(void)
+{
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL);
+ timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq);
+ dispatch_source_set_event_handler(timer, ^{ timer_ev(); } );
+
+ workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ eventq = dispatch_queue_create("heim-ipc.event-queue", NULL);
+ });
+}
+
+static void
+suspend_timer(void)
+{
+ dispatch_suspend(timer);
+}
+
+static void
+restart_timer(void)
+{
+ dispatch_sync(timerq, ^{ set_timer(); });
+ dispatch_resume(timer);
+}
+
+struct mach_service {
+ mach_port_t sport;
+ dispatch_source_t source;
+ dispatch_queue_t queue;
+};
+
+struct mach_call_ctx {
+ mach_port_t reply_port;
+ heim_icred cred;
+ heim_idata req;
+};
+
+
+static void
+mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
+{
+ struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
+ heim_ipc_message_inband_t replyin;
+ mach_msg_type_number_t replyinCnt = 0;
+ heim_ipc_message_outband_t replyout = 0;
+ mach_msg_type_number_t replyoutCnt = 0;
+
+ if (returnvalue) {
+ /* on error, no reply */
+ } else if (reply->length < 2048) {
+ replyinCnt = reply->length;
+ memcpy(replyin, reply->data, replyinCnt);
+ } else {
+ vm_read(mach_task_self(),
+ (vm_address_t)reply->data, reply->length,
+ (vm_address_t *)&replyout, &replyoutCnt);
+ }
+
+ mheim_ripc_call_reply(s->reply_port, returnvalue,
+ replyin, replyinCnt,
+ replyout, replyoutCnt);
+
+ heim_ipc_free_cred(s->cred);
+ free(s->req.data);
+ free(s);
+ restart_timer();
+}
+
+static void
+mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
+{
+ struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
+ heim_ipc_message_inband_t replyin;
+ mach_msg_type_number_t replyinCnt = 0;
+ heim_ipc_message_outband_t replyout = 0;
+ mach_msg_type_number_t replyoutCnt = 0;
+
+ if (returnvalue) {
+ /* on error, no reply */
+ } else if (reply->length < 2048) {
+ replyinCnt = reply->length;
+ memcpy(replyin, reply->data, replyinCnt);
+ } else {
+ vm_read(mach_task_self(),
+ (vm_address_t)reply->data, reply->length,
+ (vm_address_t *)&replyout, &replyoutCnt);
+ }
+
+ mheim_aipc_acall_reply(s->reply_port, returnvalue,
+ replyin, replyinCnt,
+ replyout, replyoutCnt);
+ heim_ipc_free_cred(s->cred);
+ free(s->req.data);
+ free(s);
+ restart_timer();
+}
+
+
+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)
+{
+ heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
+ struct mach_call_ctx *s;
+ kern_return_t kr;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ au_asid_t session;
+
+ *replyout = NULL;
+ *replyoutCnt = 0;
+ *replyinCnt = 0;
+
+ s = malloc(sizeof(*s));
+ if (s == NULL)
+ return KERN_MEMORY_FAILURE; /* XXX */
+
+ s->reply_port = reply_port;
+
+ audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
+
+ kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
+ if (kr) {
+ free(s);
+ return kr;
+ }
+
+ suspend_timer();
+
+ if (requestinCnt) {
+ s->req.data = malloc(requestinCnt);
+ memcpy(s->req.data, requestin, requestinCnt);
+ s->req.length = requestinCnt;
+ } else {
+ s->req.data = malloc(requestoutCnt);
+ memcpy(s->req.data, requestout, requestoutCnt);
+ s->req.length = requestoutCnt;
+ }
+
+ dispatch_async(workq, ^{
+ (ctx->callback)(ctx->userctx, &s->req, s->cred,
+ mach_complete_sync, (heim_sipc_call)s);
+ });
+
+ return MIG_NO_REPLY;
+}
+
+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)
+{
+ heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
+ struct mach_call_ctx *s;
+ kern_return_t kr;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ au_asid_t session;
+
+ s = malloc(sizeof(*s));
+ if (s == NULL)
+ return KERN_MEMORY_FAILURE; /* XXX */
+
+ s->reply_port = reply_port;
+
+ audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
+
+ kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
+ if (kr) {
+ free(s);
+ return kr;
+ }
+
+ suspend_timer();
+
+ if (requestinCnt) {
+ s->req.data = malloc(requestinCnt);
+ memcpy(s->req.data, requestin, requestinCnt);
+ s->req.length = requestinCnt;
+ } else {
+ s->req.data = malloc(requestoutCnt);
+ memcpy(s->req.data, requestout, requestoutCnt);
+ s->req.length = requestoutCnt;
+ }
+
+ dispatch_async(workq, ^{
+ (ctx->callback)(ctx->userctx, &s->req, s->cred,
+ mach_complete_async, (heim_sipc_call)s);
+ });
+
+ return KERN_SUCCESS;
+}
+
+static int
+mach_init(const char *service, mach_port_t sport, heim_sipc ctx)
+{
+ struct mach_service *s;
+ char *name;
+
+ init_globals();
+
+ s = calloc(1, sizeof(*s));
+ if (s == NULL)
+ return ENOMEM;
+
+ asprintf(&name, "heim-ipc-mach-%s", service);
+
+ s->queue = dispatch_queue_create(name, NULL);
+ free(name);
+ s->sport = sport;
+
+ s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+ s->sport, 0, s->queue);
+ if (s->source == NULL) {
+ dispatch_release(s->queue);
+ free(s);
+ return ENOMEM;
+ }
+ ctx->mech = s;
+
+ dispatch_set_context(s->queue, ctx);
+ dispatch_set_context(s->source, s);
+
+ dispatch_source_set_event_handler(s->source, ^{
+ dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server);
+ });
+
+ dispatch_source_set_cancel_handler(s->source, ^{
+ heim_sipc sctx = dispatch_get_context(dispatch_get_current_queue());
+ struct mach_service *st = sctx->mech;
+ mach_port_mod_refs(mach_task_self(), st->sport,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ dispatch_release(st->queue);
+ dispatch_release(st->source);
+ free(st);
+ free(sctx);
+ });
+
+ dispatch_resume(s->source);
+
+ return 0;
+}
+
+static int
+mach_release(heim_sipc ctx)
+{
+ struct mach_service *s = ctx->mech;
+ dispatch_source_cancel(s->source);
+ dispatch_release(s->source);
+ return 0;
+}
+
+static mach_port_t
+mach_checkin_or_register(const char *service)
+{
+ mach_port_t mp;
+ kern_return_t kr;
+
+ kr = bootstrap_check_in(bootstrap_port, service, &mp);
+ if (kr == KERN_SUCCESS)
+ return mp;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
+ /* Pre SnowLeopard version */
+ kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
+ if (kr != KERN_SUCCESS)
+ return MACH_PORT_NULL;
+
+ kr = mach_port_insert_right(mach_task_self(), mp, mp,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (kr != KERN_SUCCESS) {
+ mach_port_destroy(mach_task_self(), mp);
+ return MACH_PORT_NULL;
+ }
+
+ kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp);
+ if (kr != KERN_SUCCESS) {
+ mach_port_destroy(mach_task_self(), mp);
+ return MACH_PORT_NULL;
+ }
+
+ return mp;
+#else
+ return MACH_PORT_NULL;
+#endif
+}
+
+
+#endif /* __APPLE__ && HAVE_GCD */
+
+
+int
+heim_sipc_launchd_mach_init(const char *service,
+ heim_ipc_callback callback,
+ void *user, heim_sipc *ctx)
+{
+#if defined(__APPLE__) && defined(HAVE_GCD)
+ mach_port_t sport = MACH_PORT_NULL;
+ heim_sipc c = NULL;
+ int ret;
+
+ *ctx = NULL;
+
+ sport = mach_checkin_or_register(service);
+ if (sport == MACH_PORT_NULL) {
+ ret = ENOENT;
+ goto error;
+ }
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ c->release = mach_release;
+ c->userctx = user;
+ c->callback = callback;
+
+ ret = mach_init(service, sport, c);
+ if (ret)
+ goto error;
+
+ *ctx = c;
+ return 0;
+ error:
+ if (c)
+ free(c);
+ if (sport != MACH_PORT_NULL)
+ mach_port_mod_refs(mach_task_self(), sport,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ return ret;
+#else /* !(__APPLE__ && HAVE_GCD) */
+ *ctx = NULL;
+ return EINVAL;
+#endif /* __APPLE__ && HAVE_GCD */
+}
+
+struct client {
+ int fd;
+ heim_ipc_callback callback;
+ void *userctx;
+ int flags;
+#define LISTEN_SOCKET 1
+#define WAITING_READ 2
+#define WAITING_WRITE 4
+#define WAITING_CLOSE 8
+
+#define HTTP_REPLY 16
+#define DOOR_FD 32
+
+#define INHERIT_MASK 0xffff0000
+#define INCLUDE_ERROR_CODE (1 << 16)
+#define ALLOW_HTTP (1<<17)
+#define UNIX_SOCKET (1<<18)
+ unsigned calls;
+ size_t ptr, len;
+ uint8_t *inmsg;
+ size_t olen;
+ uint8_t *outmsg;
+#ifdef HAVE_GCD
+ dispatch_source_t in;
+ dispatch_source_t out;
+#endif
+ struct {
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ } unixrights;
+};
+
+#ifndef HAVE_GCD
+static unsigned num_clients = 0;
+static struct client **clients = NULL;
+#endif
+
+static void handle_read(struct client *);
+static void handle_write(struct client *);
+static int maybe_close(struct client *);
+
+/*
+ * Update peer credentials from socket.
+ *
+ * SCM_CREDS can only be updated the first time there is read data to
+ * read from the filedescriptor, so if we read do it before this
+ * point, the cred data might not be is not there yet.
+ */
+
+static int
+update_client_creds(struct client *c)
+{
+#ifdef HAVE_GETPEERUCRED
+ /* Solaris 10 */
+ {
+ ucred_t *peercred = NULL;
+
+ if (getpeerucred(c->fd, &peercred) == 0) {
+ c->unixrights.uid = ucred_geteuid(peercred);
+ c->unixrights.gid = ucred_getegid(peercred);
+ c->unixrights.pid = 0;
+ ucred_free(peercred);
+ return 1;
+ }
+ }
+#endif
+#ifdef HAVE_GETPEEREID
+ /* FreeBSD, OpenBSD */
+ {
+ uid_t uid;
+ gid_t gid;
+
+ if (getpeereid(c->fd, &uid, &gid) == 0) {
+ c->unixrights.uid = uid;
+ c->unixrights.gid = gid;
+ c->unixrights.pid = 0;
+ return 1;
+ }
+ }
+#endif
+#if defined(SO_PEERCRED) && defined(__linux__)
+ /* Linux */
+ {
+ struct ucred pc;
+ socklen_t pclen = sizeof(pc);
+
+ if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
+ c->unixrights.uid = pc.uid;
+ c->unixrights.gid = pc.gid;
+ c->unixrights.pid = pc.pid;
+ return 1;
+ }
+ }
+#endif
+#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
+ {
+ struct xucred peercred;
+ socklen_t peercredlen = sizeof(peercred);
+
+ if (getsockopt(c->fd, LOCAL_PEERCRED, 1,
+ (void *)&peercred, &peercredlen) == 0
+ && peercred.cr_version == XUCRED_VERSION)
+ {
+ c->unixrights.uid = peercred.cr_uid;
+ c->unixrights.gid = peercred.cr_gid;
+ c->unixrights.pid = 0;
+ return 1;
+ }
+ }
+#endif
+#if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
+ /* NetBSD */
+ if (c->unixrights.uid == (uid_t)-1) {
+ struct msghdr msg;
+ socklen_t crmsgsize;
+ void *crmsg;
+ struct cmsghdr *cmp;
+ struct sockcred *sc;
+
+ memset(&msg, 0, sizeof(msg));
+ crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
+ if (crmsgsize == 0)
+ return 1 ;
+
+ crmsg = malloc(crmsgsize);
+ if (crmsg == NULL)
+ goto failed_scm_creds;
+
+ memset(crmsg, 0, crmsgsize);
+
+ msg.msg_control = crmsg;
+ msg.msg_controllen = crmsgsize;
+
+ if (recvmsg(c->fd, &msg, 0) < 0) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ cmp = CMSG_FIRSTHDR(&msg);
+ if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
+ free(crmsg);
+ goto failed_scm_creds;
+ }
+
+ sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
+
+ c->unixrights.uid = sc->sc_euid;
+ c->unixrights.gid = sc->sc_egid;
+ c->unixrights.pid = 0;
+
+ free(crmsg);
+ return 1;
+ } else {
+ /* we already got the cred, just return it */
+ return 1;
+ }
+ failed_scm_creds:
+#endif
+ return 0;
+}
+
+static struct client *
+add_new_socket(int fd,
+ int flags,
+ heim_ipc_callback callback,
+ void *userctx)
+{
+ struct client *c;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ return NULL;
+
+ if (flags & LISTEN_SOCKET) {
+ c->fd = fd;
+ } else if (flags & DOOR_FD) {
+ c->fd = -1; /* cannot poll a door descriptor */
+ } else {
+ c->fd = accept(fd, NULL, NULL);
+ if(c->fd < 0) {
+ free(c);
+ return NULL;
+ }
+ }
+
+ c->flags = flags;
+ c->callback = callback;
+ c->userctx = userctx;
+
+ socket_set_nonblocking(fd, 1);
+
+#ifdef HAVE_GCD
+ init_globals();
+
+ c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
+ c->fd, 0, eventq);
+ c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
+ c->fd, 0, eventq);
+
+ dispatch_source_set_event_handler(c->in, ^{
+ int rw = (c->flags & WAITING_WRITE);
+ handle_read(c);
+ if (rw == 0 && (c->flags & WAITING_WRITE))
+ dispatch_resume(c->out);
+ if ((c->flags & WAITING_READ) == 0)
+ dispatch_suspend(c->in);
+ maybe_close(c);
+ });
+ dispatch_source_set_event_handler(c->out, ^{
+ handle_write(c);
+ if ((c->flags & WAITING_WRITE) == 0) {
+ dispatch_suspend(c->out);
+ }
+ maybe_close(c);
+ });
+
+ dispatch_resume(c->in);
+#else
+ clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1));
+ clients[num_clients] = c;
+ num_clients++;
+#endif
+
+ return c;
+}
+
+static int
+maybe_close(struct client *c)
+{
+ if (c->calls != 0)
+ return 0;
+ if (c->flags & (WAITING_READ|WAITING_WRITE))
+ return 0;
+
+#ifdef HAVE_GCD
+ dispatch_source_cancel(c->in);
+ if ((c->flags & WAITING_READ) == 0)
+ dispatch_resume(c->in);
+ dispatch_release(c->in);
+
+ dispatch_source_cancel(c->out);
+ if ((c->flags & WAITING_WRITE) == 0)
+ dispatch_resume(c->out);
+ dispatch_release(c->out);
+#endif
+ close(c->fd); /* ref count fd close */
+ free(c->inmsg);
+ free(c);
+ return 1;
+}
+
+
+struct socket_call {
+ heim_idata in;
+ struct client *c;
+ heim_icred cred;
+};
+
+static void
+output_data(struct client *c, const void *data, size_t len)
+{
+ if (c->olen + len < c->olen)
+ abort();
+ c->outmsg = erealloc(c->outmsg, c->olen + len);
+ memcpy(&c->outmsg[c->olen], data, len);
+ c->olen += len;
+ c->flags |= WAITING_WRITE;
+}
+
+static void
+socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
+{
+ struct socket_call *sc = (struct socket_call *)ctx;
+ struct client *c = sc->c;
+
+ /* double complete ? */
+ if (c == NULL)
+ abort();
+
+ if ((c->flags & WAITING_CLOSE) == 0) {
+ uint32_t u32;
+
+ /* length */
+ u32 = htonl(reply->length);
+ output_data(c, &u32, sizeof(u32));
+
+ /* return value */
+ if (c->flags & INCLUDE_ERROR_CODE) {
+ u32 = htonl(returnvalue);
+ output_data(c, &u32, sizeof(u32));
+ }
+
+ /* data */
+ output_data(c, reply->data, reply->length);
+
+ /* if HTTP, close connection */
+ if (c->flags & HTTP_REPLY) {
+ c->flags |= WAITING_CLOSE;
+ c->flags &= ~WAITING_READ;
+ }
+ }
+
+ c->calls--;
+ if (sc->cred)
+ heim_ipc_free_cred(sc->cred);
+ free(sc->in.data);
+ sc->c = NULL; /* so we can catch double complete */
+ free(sc);
+
+ maybe_close(c);
+}
+
+/* remove HTTP %-quoting from buf */
+static int
+de_http(char *buf)
+{
+ unsigned char *p, *q;
+ for(p = q = (unsigned char *)buf; *p; p++, q++) {
+ if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
+ unsigned int x;
+ if(sscanf((char *)p + 1, "%2x", &x) != 1)
+ return -1;
+ *q = x;
+ p += 2;
+ } else
+ *q = *p;
+ }
+ *q = '\0';
+ return 0;
+}
+
+static struct socket_call *
+handle_http_tcp(struct client *c)
+{
+ struct socket_call *cs;
+ char *s, *p, *t;
+ void *data;
+ char *proto;
+ int len;
+
+ s = (char *)c->inmsg;
+
+ p = strstr(s, "\r\n");
+ if (p == NULL)
+ return NULL;
+
+ *p = 0;
+
+ p = NULL;
+ t = strtok_r(s, " \t", &p);
+ if (t == NULL)
+ return NULL;
+
+ t = strtok_r(NULL, " \t", &p);
+ if (t == NULL)
+ return NULL;
+
+ data = malloc(strlen(t));
+ if (data == NULL)
+ return NULL;
+
+ if(*t == '/')
+ t++;
+ if(de_http(t) != 0) {
+ free(data);
+ return NULL;
+ }
+ proto = strtok_r(NULL, " \t", &p);
+ if (proto == NULL) {
+ free(data);
+ return NULL;
+ }
+ len = rk_base64_decode(t, data);
+ if(len <= 0){
+ const char *msg =
+ " 404 Not found\r\n"
+ "Server: Heimdal/" VERSION "\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Pragma: no-cache\r\n"
+ "Content-type: text/html\r\n"
+ "Content-transfer-encoding: 8bit\r\n\r\n"
+ "<TITLE>404 Not found</TITLE>\r\n"
+ "<H1>404 Not found</H1>\r\n"
+ "That page doesn't exist, maybe you are looking for "
+ "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
+ free(data);
+ output_data(c, proto, strlen(proto));
+ output_data(c, msg, strlen(msg));
+ return NULL;
+ }
+
+ cs = emalloc(sizeof(*cs));
+ cs->c = c;
+ cs->in.data = data;
+ cs->in.length = len;
+ c->ptr = 0;
+
+ {
+ const char *msg =
+ " 200 OK\r\n"
+ "Server: Heimdal/" VERSION "\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Pragma: no-cache\r\n"
+ "Content-type: application/octet-stream\r\n"
+ "Content-transfer-encoding: binary\r\n\r\n";
+ output_data(c, proto, strlen(proto));
+ output_data(c, msg, strlen(msg));
+ }
+
+ return cs;
+}
+
+
+static void
+handle_read(struct client *c)
+{
+ ssize_t len;
+ uint32_t dlen;
+
+ assert((c->flags & DOOR_FD) == 0);
+
+ if (c->flags & LISTEN_SOCKET) {
+ add_new_socket(c->fd,
+ WAITING_READ | (c->flags & INHERIT_MASK),
+ c->callback,
+ c->userctx);
+ return;
+ }
+
+ if (c->ptr - c->len < 1024) {
+ c->inmsg = erealloc(c->inmsg,
+ c->len + 1024);
+ c->len += 1024;
+ }
+
+ len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr);
+ if (len <= 0) {
+ c->flags |= WAITING_CLOSE;
+ c->flags &= ~WAITING_READ;
+ return;
+ }
+ c->ptr += len;
+ if (c->ptr > c->len)
+ abort();
+
+ while (c->ptr >= sizeof(dlen)) {
+ struct socket_call *cs;
+
+ if((c->flags & ALLOW_HTTP) && c->ptr >= 4 &&
+ strncmp((char *)c->inmsg, "GET ", 4) == 0 &&
+ strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) {
+
+ /* remove the trailing \r\n\r\n so the string is NUL terminated */
+ c->inmsg[c->ptr - 4] = '\0';
+
+ c->flags |= HTTP_REPLY;
+
+ cs = handle_http_tcp(c);
+ if (cs == NULL) {
+ c->flags |= WAITING_CLOSE;
+ c->flags &= ~WAITING_READ;
+ break;
+ }
+ } else {
+ memcpy(&dlen, c->inmsg, sizeof(dlen));
+ dlen = ntohl(dlen);
+
+ if (dlen > MAX_PACKET_SIZE) {
+ c->flags |= WAITING_CLOSE;
+ c->flags &= ~WAITING_READ;
+ return;
+ }
+ if (dlen > c->ptr - sizeof(dlen)) {
+ break;
+ }
+
+ cs = emalloc(sizeof(*cs));
+ cs->c = c;
+ cs->in.data = emalloc(dlen);
+ memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
+ cs->in.length = dlen;
+ cs->cred = NULL;
+
+ c->ptr -= sizeof(dlen) + dlen;
+ memmove(c->inmsg,
+ c->inmsg + sizeof(dlen) + dlen,
+ c->ptr);
+ }
+
+ c->calls++;
+
+ if ((c->flags & UNIX_SOCKET) != 0) {
+ if (update_client_creds(c))
+ _heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid,
+ c->unixrights.pid, -1, &cs->cred);
+ }
+
+ c->callback(c->userctx, &cs->in,
+ cs->cred, socket_complete,
+ (heim_sipc_call)cs);
+ }
+}
+
+static void
+handle_write(struct client *c)
+{
+ ssize_t len;
+
+ len = write(c->fd, c->outmsg, c->olen);
+ if (len <= 0) {
+ c->flags |= WAITING_CLOSE;
+ c->flags &= ~(WAITING_WRITE);
+ } else if (c->olen != (size_t)len) {
+ memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len);
+ c->olen -= len;
+ } else {
+ c->olen = 0;
+ free(c->outmsg);
+ c->outmsg = NULL;
+ c->flags &= ~(WAITING_WRITE);
+ }
+}
+
+
+#ifndef HAVE_GCD
+
+static void
+process_loop(void)
+{
+ struct pollfd *fds;
+ unsigned n;
+ unsigned num_fds;
+
+ while (num_clients > 0) {
+
+ fds = malloc(num_clients * sizeof(fds[0]));
+ if(fds == NULL)
+ abort();
+
+ num_fds = num_clients;
+
+ for (n = 0 ; n < num_fds; n++) {
+ fds[n].fd = clients[n]->fd;
+ fds[n].events = 0;
+ if (clients[n]->flags & WAITING_READ)
+ fds[n].events |= POLLIN;
+ if (clients[n]->flags & WAITING_WRITE)
+ fds[n].events |= POLLOUT;
+
+ fds[n].revents = 0;
+ }
+
+ while (poll(fds, num_fds, -1) == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ err(1, "poll(2) failed");
+ }
+
+ for (n = 0 ; n < num_fds; n++) {
+ if (clients[n] == NULL)
+ continue;
+ if (fds[n].revents & POLLIN)
+ handle_read(clients[n]);
+ if (fds[n].revents & POLLOUT)
+ handle_write(clients[n]);
+ if (fds[n].revents & POLLERR)
+ clients[n]->flags |= WAITING_CLOSE;
+ }
+
+ n = 0;
+ while (n < num_clients) {
+ struct client *c = clients[n];
+ if (maybe_close(c)) {
+ if (n < num_clients - 1)
+ clients[n] = clients[num_clients - 1];
+ num_clients--;
+ } else
+ n++;
+ }
+
+ free(fds);
+ }
+}
+
+#endif
+
+static int
+socket_release(heim_sipc ctx)
+{
+ struct client *c = ctx->mech;
+ c->flags |= WAITING_CLOSE;
+ return 0;
+}
+
+int
+heim_sipc_stream_listener(int fd, int type,
+ heim_ipc_callback callback,
+ void *user, heim_sipc *ctx)
+{
+ heim_sipc ct;
+ struct client *c;
+
+ if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP)))
+ return EINVAL;
+
+ ct = calloc(1, sizeof(*ct));
+ if (ct == NULL)
+ return ENOMEM;
+
+ switch (type) {
+ case HEIM_SIPC_TYPE_IPC:
+ c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user);
+ break;
+ case HEIM_SIPC_TYPE_UINT32:
+ c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
+ break;
+ case HEIM_SIPC_TYPE_HTTP:
+ case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP:
+ c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user);
+ break;
+ default:
+ free(ct);
+ return EINVAL;
+ }
+
+ ct->mech = c;
+ ct->release = socket_release;
+
+ c->unixrights.uid = (uid_t) -1;
+ c->unixrights.gid = (gid_t) -1;
+ c->unixrights.pid = (pid_t) 0;
+
+ *ctx = ct;
+ return 0;
+}
+
+int
+heim_sipc_service_unix(const char *service,
+ heim_ipc_callback callback,
+ void *user, heim_sipc *ctx)
+{
+ struct sockaddr_un un;
+ const char *d = secure_getenv("HEIM_IPC_DIR");
+ int fd, ret;
+
+ if (strncasecmp(service, "UNIX:", sizeof("UNIX:") - 1) == 0)
+ service += sizeof("UNIX:") - 1;
+
+ un.sun_family = AF_UNIX;
+
+ if (snprintf(un.sun_path, sizeof(un.sun_path),
+ "%s/.heim_%s-socket", d ? d : _PATH_VARRUN,
+ service) > sizeof(un.sun_path) + sizeof("-s") - 1)
+ return ENAMETOOLONG;
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ socket_set_reuseaddr(fd, 1);
+#ifdef LOCAL_CREDS
+ {
+ int one = 1;
+ (void) setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
+ }
+#endif
+
+ unlink(un.sun_path);
+
+ if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
+ close(fd);
+ return errno;
+ }
+
+ if (listen(fd, SOMAXCONN) < 0) {
+ close(fd);
+ return errno;
+ }
+
+ (void) chmod(un.sun_path, 0666);
+
+ ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
+ callback, user, ctx);
+ if (ret == 0) {
+ struct client *c = (*ctx)->mech;
+ c->flags |= UNIX_SOCKET;
+ }
+
+ return ret;
+}
+
+#ifdef HAVE_DOOR_CREATE
+#include <door.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "heim_threads.h"
+
+static HEIMDAL_thread_key door_key;
+
+struct door_call {
+ heim_idata in;
+ door_desc_t *dp;
+ heim_icred cred;
+};
+
+struct door_reply {
+ int returnvalue;
+ size_t length;
+ unsigned char data[1];
+};
+
+static int
+door_release(heim_sipc ctx)
+{
+ struct client *c = ctx->mech;
+ return 0;
+}
+
+static void
+door_reply_destroy(void *data)
+{
+ free(data);
+}
+
+static void
+door_key_create(void *key)
+{
+ int ret;
+
+ HEIMDAL_key_create((HEIMDAL_thread_key *)key, door_reply_destroy, ret);
+}
+
+static void
+door_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
+{
+ static heim_base_once_t once = HEIM_BASE_ONCE_INIT;
+ struct door_call *cs = (struct door_call *)ctx;
+ size_t rlen;
+ struct door_reply *r = NULL;
+ union {
+ struct door_reply reply;
+ char buffer[offsetof(struct door_reply, data) + BUFSIZ];
+ } replyBuf;
+
+ heim_base_once_f(&once, &door_key, door_key_create);
+
+ /* door_return() doesn't return; don't leak cred */
+ heim_ipc_free_cred(cs->cred);
+
+error_reply:
+ rlen = offsetof(struct door_reply, data);
+ if (returnvalue == 0)
+ rlen += reply->length;
+
+ /* long replies (> BUFSIZ) are allocated from the heap */
+ if (rlen > BUFSIZ) {
+ int ret;
+
+ /* door_return() doesn't return, so stash reply buffer in TLS */
+ r = realloc(HEIMDAL_getspecific(door_key), rlen);
+ if (r == NULL) {
+ returnvalue = EAGAIN; /* don't leak ENOMEM to caller */
+ goto error_reply;
+ }
+
+ HEIMDAL_setspecific(door_key, r, ret);
+ } else {
+ r = &replyBuf.reply;
+ }
+
+ r->returnvalue = returnvalue;
+ if (r->returnvalue == 0) {
+ r->length = reply->length;
+ memcpy(r->data, reply->data, reply->length);
+ } else {
+ r->length = 0;
+ }
+
+ door_return((char *)r, rlen, NULL, 0);
+}
+
+static void
+door_callback(void *cookie,
+ char *argp,
+ size_t arg_size,
+ door_desc_t *dp,
+ uint_t n_desc)
+{
+ heim_sipc c = (heim_sipc)cookie;
+ struct door_call cs = { 0 };
+ ucred_t *peercred = NULL;
+
+ if (door_ucred(&peercred) < 0)
+ return;
+
+ _heim_ipc_create_cred(ucred_geteuid(peercred),
+ ucred_getegid(peercred),
+ ucred_getpid(peercred),
+ -1,
+ &cs.cred);
+ ucred_free(peercred);
+
+ cs.dp = dp;
+ cs.in.data = argp;
+ cs.in.length = arg_size;
+
+ c->callback(c->userctx, &cs.in, cs.cred, door_complete, (heim_sipc_call)&cs);
+}
+
+int
+heim_sipc_service_door(const char *service,
+ heim_ipc_callback callback,
+ void *user, heim_sipc *ctx)
+{
+ char path[PATH_MAX];
+ int fd = -1, dfd = -1, ret;
+ heim_sipc ct = NULL;
+ struct client *c = NULL;
+
+ ct = calloc(1, sizeof(*ct));
+ if (ct == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ ct->release = door_release;
+ ct->userctx = user;
+ ct->callback = callback;
+
+ if (snprintf(path, sizeof(path), "/var/run/.heim_%s-door",
+ service) >= sizeof(path) + sizeof("-d") - 1) {
+ ret = ENAMETOOLONG;
+ goto cleanup;
+ }
+ fd = door_create(door_callback, ct, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+ if (fd < 0) {
+ ret = errno;
+ goto cleanup;
+ }
+
+ fdetach(path);
+ dfd = open(path, O_RDWR | O_CREAT, 0666);
+ if (dfd < 0) {
+ ret = errno;
+ goto cleanup;
+ }
+ (void) fchmod(dfd, 0666); /* XXX */
+
+ if (fattach(fd, path) < 0) {
+ ret = errno;
+ goto cleanup;
+ }
+
+ c = add_new_socket(fd, DOOR_FD, callback, user);
+ ct->mech = c;
+
+ *ctx = ct;
+ ret = 0;
+
+cleanup:
+ if (ret != 0) {
+ free(ct);
+ free(c);
+ if (fd != -1)
+ close(fd);
+ }
+ if (dfd != -1)
+ close(dfd);
+
+ return ret;
+}
+#endif /* HAVE_DOOR_CREATE */
+
+/**
+ * Set the idle timeout value
+
+ * The timeout event handler is triggered recurrently every idle
+ * period `t'. The default action is rather draconian and just calls
+ * exit(0), so you might want to change this to something more
+ * graceful using heim_sipc_set_timeout_handler().
+ */
+
+void
+heim_sipc_timeout(time_t t)
+{
+#ifdef HAVE_GCD
+ static dispatch_once_t timeoutonce;
+ init_globals();
+ dispatch_sync(timerq, ^{
+ timeoutvalue = t;
+ set_timer();
+ });
+ dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); });
+#else
+ abort();
+#endif
+}
+
+/**
+ * Set the timeout event handler
+ *
+ * Replaces the default idle timeout action.
+ */
+
+void
+heim_sipc_set_timeout_handler(void (*func)(void))
+{
+#ifdef HAVE_GCD
+ init_globals();
+ dispatch_sync(timerq, ^{ timer_ev = func; });
+#else
+ abort();
+#endif
+}
+
+
+void
+heim_sipc_free_context(heim_sipc ctx)
+{
+ (ctx->release)(ctx);
+}
+
+void
+heim_ipc_main(void)
+{
+#ifdef HAVE_GCD
+ dispatch_main();
+#else
+ process_loop();
+#endif
+}
diff --git a/third_party/heimdal/lib/ipc/tc.c b/third_party/heimdal/lib/ipc/tc.c
new file mode 100644
index 0000000..e366f17
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/tc.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5-types.h>
+#include <asn1-common.h>
+#include <heim-ipc.h>
+#include <getarg.h>
+#include <err.h>
+#include <roken.h>
+
+static int help_flag;
+static int version_flag;
+
+static struct getargs args[] = {
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 'v', arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int ret)
+{
+ arg_printusage (args, num_args, NULL, "");
+ exit (ret);
+}
+
+static void
+reply(void *ctx, int errorcode, heim_idata *rep, heim_icred cred)
+{
+ printf("got reply errorcode %d, rep %.*s\n", errorcode,
+ rep->length < INT_MAX ? (int)rep->length : INT_MAX,
+ (char *)rep->data);
+ heim_ipc_semaphore_signal((heim_isemaphore)ctx); /* tell caller we are done */
+}
+
+static void
+test_ipc(const char *service)
+{
+ heim_isemaphore s;
+ heim_idata req, rep;
+ heim_ipc ipc;
+ int ret;
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "testing heim IPC via %s", service);
+
+ printf("%s\n", buf);
+
+ ret = heim_ipc_init_context(service, &ipc);
+ if (ret)
+ errx(1, "heim_ipc_init_context: %d", ret);
+
+ req.length = strlen(buf);
+ req.data = buf;
+
+ ret = heim_ipc_call(ipc, &req, &rep, NULL);
+ if (ret)
+ errx(1, "heim_ipc_call: %d", ret);
+
+ s = heim_ipc_semaphore_create(0);
+ if (s == NULL)
+ errx(1, "heim_ipc_semaphore_create");
+
+ ret = heim_ipc_async(ipc, &req, s, reply);
+ if (ret)
+ errx(1, "heim_ipc_async: %d", ret);
+
+ heim_ipc_semaphore_wait(s, HEIM_IPC_WAIT_FOREVER); /* wait for reply to complete the work */
+
+ heim_ipc_free_context(ipc);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+
+ setprogname(argv[0]);
+
+ if (getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+
+ if (help_flag)
+ usage(0);
+
+ if (version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+#ifdef __APPLE__
+ test_ipc("MACH:org.h5l.test-ipc");
+#endif
+ test_ipc("ANY:org.h5l.test-ipc");
+ test_ipc("UNIX:org.h5l.test-ipc");
+#ifdef HAVE_DOOR_CREATE
+ test_ipc("DOOR:org.h5l.test-ipc");
+#endif
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/ipc/ts-http.c b/third_party/heimdal/lib/ipc/ts-http.c
new file mode 100644
index 0000000..c3c3ce5
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/ts-http.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5-types.h>
+#include <heim-ipc.h>
+#include <getarg.h>
+#include <roken.h>
+
+static int help_flag;
+static int version_flag;
+
+static struct getargs args[] = {
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 'v', arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int ret)
+{
+ arg_printusage (args, num_args, NULL, "");
+ exit (ret);
+}
+
+static void
+test_service(void *ctx, const heim_idata *req,
+ const heim_icred cred,
+ heim_ipc_complete complete,
+ heim_sipc_call cctx)
+{
+ heim_idata rep;
+ printf("got request\n");
+ rep.length = 3;
+ rep.data = strdup("hej");
+ (*complete)(cctx, 0, &rep);
+}
+
+
+static void
+setup_sockets(void)
+{
+ struct addrinfo hints, *res, *res0;
+ int ret, s;
+ heim_sipc u;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ ret = getaddrinfo(NULL, "8080", &hints, &res0);
+ if (ret)
+ errx(1, "%s", gai_strerror(ret));
+
+ for (res = res0; res ; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s < 0) {
+ warn("socket");
+ continue;
+ }
+ socket_set_reuseaddr(s, 1);
+ socket_set_ipv6only(s, 1);
+
+ if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
+ warn("bind");
+ close(s);
+ continue;
+ }
+ listen(s, 5);
+ ret = heim_sipc_stream_listener(s, HEIM_SIPC_TYPE_HTTP,
+ test_service, NULL, &u);
+ if (ret)
+ errx(1, "heim_sipc_stream_listener: %d", ret);
+ }
+ freeaddrinfo(res0);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+
+ setprogname(argv[0]);
+
+ if (getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+
+ if (help_flag)
+ usage(0);
+
+ if (version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ setup_sockets();
+
+ heim_ipc_main();
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/ipc/ts.c b/third_party/heimdal/lib/ipc/ts.c
new file mode 100644
index 0000000..3ba5d65
--- /dev/null
+++ b/third_party/heimdal/lib/ipc/ts.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5-types.h>
+#include <heim-ipc.h>
+#include <getarg.h>
+#include <roken.h>
+
+static int help_flag;
+static int version_flag;
+
+static struct getargs args[] = {
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 'v', arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int ret)
+{
+ arg_printusage (args, num_args, NULL, "");
+ exit (ret);
+}
+
+static void
+test_service(void *ctx, const heim_idata *req,
+ const heim_icred cred,
+ heim_ipc_complete complete,
+ heim_sipc_call cctx)
+{
+ heim_idata rep;
+ char buf[128];
+
+ printf("got request via %s\n", (const char *)ctx);
+ snprintf(buf, sizeof(buf), "Hello back via %s\n", (const char *)ctx);
+ rep.data = buf;
+ rep.length = strlen(buf);
+ (*complete)(cctx, 0, &rep);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ heim_sipc u;
+ int optidx = 0;
+
+ setprogname(argv[0]);
+
+ if (getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+
+ if (help_flag)
+ usage(0);
+
+ if (version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+#if __APPLE__
+ {
+ heim_sipc mach;
+ heim_sipc_launchd_mach_init("org.h5l.test-ipc",
+ test_service, "MACH", &mach);
+ }
+#endif
+ heim_sipc_service_unix("org.h5l.test-ipc",
+ test_service, "UNIX", &u);
+#ifdef HAVE_DOOR_CREATE
+ {
+ heim_sipc door;
+ heim_sipc_service_door("org.h5l.test-ipc",
+ test_service, "DOOR", &door);
+ }
+#endif
+ heim_ipc_main();
+
+ return 0;
+}