aboutsummaryrefslogtreecommitdiff
path: root/lib/ipc/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ipc/server.c')
-rw-r--r--lib/ipc/server.c274
1 files changed, 227 insertions, 47 deletions
diff --git a/lib/ipc/server.c b/lib/ipc/server.c
index ef91f6a09044..5ada75af7d13 100644
--- a/lib/ipc/server.c
+++ b/lib/ipc/server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -122,26 +122,19 @@ 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;
+ 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 */
- 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);
+ 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,
@@ -159,31 +152,24 @@ 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;
+ 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 */
- 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);
+ 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);
+ mheim_aipc_acall_reply(s->reply_port, returnvalue,
+ replyin, replyinCnt,
+ replyout, replyoutCnt);
heim_ipc_free_cred(s->cred);
free(s->req.data);
free(s);
@@ -457,6 +443,7 @@ struct client {
#define WAITING_CLOSE 8
#define HTTP_REPLY 16
+#define DOOR_FD 32
#define INHERIT_MASK 0xffff0000
#define INCLUDE_ERROR_CODE (1 << 16)
@@ -501,9 +488,9 @@ update_client_creds(struct client *c)
#ifdef HAVE_GETPEERUCRED
/* Solaris 10 */
{
- ucred_t *peercred;
+ ucred_t *peercred = NULL;
- if (getpeerucred(c->fd, &peercred) != 0) {
+ if (getpeerucred(c->fd, &peercred) == 0) {
c->unixrights.uid = ucred_geteuid(peercred);
c->unixrights.gid = ucred_getegid(peercred);
c->unixrights.pid = 0;
@@ -612,7 +599,6 @@ update_client_creds(struct client *c)
return 0;
}
-
static struct client *
add_new_socket(int fd,
int flags,
@@ -620,7 +606,6 @@ add_new_socket(int fd,
void *userctx)
{
struct client *c;
- int fileflags;
c = calloc(1, sizeof(*c));
if (c == NULL)
@@ -628,6 +613,8 @@ add_new_socket(int fd,
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) {
@@ -640,8 +627,7 @@ add_new_socket(int fd,
c->callback = callback;
c->userctx = userctx;
- fileflags = fcntl(c->fd, F_GETFL, 0);
- fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK);
+ socket_set_nonblocking(fd, 1);
#ifdef HAVE_GCD
init_globals();
@@ -698,6 +684,7 @@ maybe_close(struct client *c)
dispatch_release(c->out);
#endif
close(c->fd); /* ref count fd close */
+ free(c->inmsg);
free(c);
return 1;
}
@@ -870,6 +857,8 @@ 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),
@@ -930,6 +919,7 @@ handle_read(struct client *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,
@@ -1009,15 +999,12 @@ process_loop(void)
for (n = 0 ; n < num_fds; n++) {
if (clients[n] == NULL)
continue;
- if (fds[n].revents & POLLERR) {
- clients[n]->flags |= WAITING_CLOSE;
- 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;
@@ -1050,12 +1037,16 @@ heim_sipc_stream_listener(int fd, int type,
heim_ipc_callback callback,
void *user, heim_sipc *ctx)
{
- heim_sipc ct = calloc(1, sizeof(*ct));
+ 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);
@@ -1089,12 +1080,18 @@ heim_sipc_service_unix(const char *service,
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;
- snprintf(un.sun_path, sizeof(un.sun_path),
- "/var/run/.heim_%s-socket", service);
+ 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;
@@ -1103,7 +1100,7 @@ heim_sipc_service_unix(const char *service,
#ifdef LOCAL_CREDS
{
int one = 1;
- setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
+ (void) setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
}
#endif
@@ -1119,7 +1116,7 @@ heim_sipc_service_unix(const char *service,
return errno;
}
- chmod(un.sun_path, 0666);
+ (void) chmod(un.sun_path, 0666);
ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
callback, user, ctx);
@@ -1131,6 +1128,190 @@ heim_sipc_service_unix(const char *service,
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
@@ -1189,4 +1370,3 @@ heim_ipc_main(void)
process_loop();
#endif
}
-