diff options
Diffstat (limited to 'third_party/heimdal/lib/ipc')
-rw-r--r-- | third_party/heimdal/lib/ipc/Makefile.am | 72 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/client.c | 610 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/common.c | 206 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/heim-ipc.h | 133 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/heim_ipc.defs | 66 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/heim_ipc_async.defs | 56 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/heim_ipc_reply.defs | 51 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/heim_ipc_types.h | 44 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/hi_locl.h | 83 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/server.c | 1385 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/tc.c | 138 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/ts-http.c | 136 | ||||
-rw-r--r-- | third_party/heimdal/lib/ipc/ts.c | 116 |
13 files changed, 3096 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..6915175 --- /dev/null +++ b/third_party/heimdal/lib/ipc/Makefile.am @@ -0,0 +1,72 @@ +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) + +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..39e1b49 --- /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)); +}; + +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 { + 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..40601b9 --- /dev/null +++ b/third_party/heimdal/lib/ipc/server.c @@ -0,0 +1,1385 @@ +/* + * 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; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyoutCnt; + kern_return_t kr; + + if (returnvalue) { + /* on error, no reply */ + replyinCnt = 0; + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else { + replyinCnt = 0; + kr = 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; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyoutCnt; + kern_return_t kr; + + if (returnvalue) { + /* on error, no reply */ + replyinCnt = 0; + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else { + replyinCnt = 0; + kr = vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); + } + + kr = 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; + int fileflags; + + 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; + + fileflags = fcntl(c->fd, F_GETFL, 0); + fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK); + +#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); + 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; + + 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; + } + + 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; + } + 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; +} |