1226031Sstas/* 2226031Sstas * Copyright (c) 2009 Kungliga Tekniska H�gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7226031Sstas * 8226031Sstas * Redistribution and use in source and binary forms, with or without 9226031Sstas * modification, are permitted provided that the following conditions 10226031Sstas * are met: 11226031Sstas * 12226031Sstas * 1. Redistributions of source code must retain the above copyright 13226031Sstas * notice, this list of conditions and the following disclaimer. 14226031Sstas * 15226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 16226031Sstas * notice, this list of conditions and the following disclaimer in the 17226031Sstas * documentation and/or other materials provided with the distribution. 18226031Sstas * 19226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 20226031Sstas * may be used to endorse or promote products derived from this software 21226031Sstas * without specific prior written permission. 22226031Sstas * 23226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33226031Sstas * SUCH DAMAGE. 34226031Sstas */ 35226031Sstas 36226031Sstas#include "hi_locl.h" 37226031Sstas#include <assert.h> 38226031Sstas 39226031Sstas#define MAX_PACKET_SIZE (128 * 1024) 40226031Sstas 41226031Sstasstruct heim_sipc { 42226031Sstas int (*release)(heim_sipc ctx); 43226031Sstas heim_ipc_callback callback; 44226031Sstas void *userctx; 45226031Sstas void *mech; 46226031Sstas}; 47226031Sstas 48226031Sstas#if defined(__APPLE__) && defined(HAVE_GCD) 49226031Sstas 50226031Sstas#include "heim_ipcServer.h" 51226031Sstas#include "heim_ipc_reply.h" 52226031Sstas#include "heim_ipc_async.h" 53226031Sstas 54226031Sstasstatic dispatch_source_t timer; 55226031Sstasstatic dispatch_queue_t timerq; 56226031Sstasstatic uint64_t timeoutvalue; 57226031Sstas 58226031Sstasstatic dispatch_queue_t eventq; 59226031Sstas 60226031Sstasstatic dispatch_queue_t workq; 61226031Sstas 62226031Sstasstatic void 63226031Sstasdefault_timer_ev(void) 64226031Sstas{ 65226031Sstas exit(0); 66226031Sstas} 67226031Sstas 68226031Sstasstatic void (*timer_ev)(void) = default_timer_ev; 69226031Sstas 70226031Sstasstatic void 71226031Sstasset_timer(void) 72226031Sstas{ 73226031Sstas dispatch_source_set_timer(timer, 74226031Sstas dispatch_time(DISPATCH_TIME_NOW, 75226031Sstas timeoutvalue * NSEC_PER_SEC), 76226031Sstas timeoutvalue * NSEC_PER_SEC, 1000000); 77226031Sstas} 78226031Sstas 79226031Sstasstatic void 80226031Sstasinit_globals(void) 81226031Sstas{ 82226031Sstas static dispatch_once_t once; 83226031Sstas dispatch_once(&once, ^{ 84226031Sstas timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL); 85226031Sstas timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq); 86226031Sstas dispatch_source_set_event_handler(timer, ^{ timer_ev(); } ); 87226031Sstas 88226031Sstas workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 89226031Sstas eventq = dispatch_queue_create("heim-ipc.event-queue", NULL); 90226031Sstas }); 91226031Sstas} 92226031Sstas 93226031Sstasstatic void 94226031Sstassuspend_timer(void) 95226031Sstas{ 96226031Sstas dispatch_suspend(timer); 97226031Sstas} 98226031Sstas 99226031Sstasstatic void 100226031Sstasrestart_timer(void) 101226031Sstas{ 102226031Sstas dispatch_sync(timerq, ^{ set_timer(); }); 103226031Sstas dispatch_resume(timer); 104226031Sstas} 105226031Sstas 106226031Sstasstruct mach_service { 107226031Sstas mach_port_t sport; 108226031Sstas dispatch_source_t source; 109226031Sstas dispatch_queue_t queue; 110226031Sstas}; 111226031Sstas 112226031Sstasstruct mach_call_ctx { 113226031Sstas mach_port_t reply_port; 114226031Sstas heim_icred cred; 115226031Sstas heim_idata req; 116226031Sstas}; 117226031Sstas 118226031Sstas 119226031Sstasstatic void 120226031Sstasmach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply) 121226031Sstas{ 122226031Sstas struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; 123226031Sstas heim_ipc_message_inband_t replyin; 124226031Sstas mach_msg_type_number_t replyinCnt; 125226031Sstas heim_ipc_message_outband_t replyout; 126226031Sstas mach_msg_type_number_t replyoutCnt; 127226031Sstas kern_return_t kr; 128226031Sstas 129226031Sstas if (returnvalue) { 130226031Sstas /* on error, no reply */ 131226031Sstas replyinCnt = 0; 132226031Sstas replyout = 0; replyoutCnt = 0; 133226031Sstas kr = KERN_SUCCESS; 134226031Sstas } else if (reply->length < 2048) { 135226031Sstas replyinCnt = reply->length; 136226031Sstas memcpy(replyin, reply->data, replyinCnt); 137226031Sstas replyout = 0; replyoutCnt = 0; 138226031Sstas kr = KERN_SUCCESS; 139226031Sstas } else { 140226031Sstas replyinCnt = 0; 141226031Sstas kr = vm_read(mach_task_self(), 142226031Sstas (vm_address_t)reply->data, reply->length, 143226031Sstas (vm_address_t *)&replyout, &replyoutCnt); 144226031Sstas } 145226031Sstas 146226031Sstas mheim_ripc_call_reply(s->reply_port, returnvalue, 147226031Sstas replyin, replyinCnt, 148226031Sstas replyout, replyoutCnt); 149226031Sstas 150226031Sstas heim_ipc_free_cred(s->cred); 151226031Sstas free(s->req.data); 152226031Sstas free(s); 153226031Sstas restart_timer(); 154226031Sstas} 155226031Sstas 156226031Sstasstatic void 157226031Sstasmach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply) 158226031Sstas{ 159226031Sstas struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; 160226031Sstas heim_ipc_message_inband_t replyin; 161226031Sstas mach_msg_type_number_t replyinCnt; 162226031Sstas heim_ipc_message_outband_t replyout; 163226031Sstas mach_msg_type_number_t replyoutCnt; 164226031Sstas kern_return_t kr; 165226031Sstas 166226031Sstas if (returnvalue) { 167226031Sstas /* on error, no reply */ 168226031Sstas replyinCnt = 0; 169226031Sstas replyout = 0; replyoutCnt = 0; 170226031Sstas kr = KERN_SUCCESS; 171226031Sstas } else if (reply->length < 2048) { 172226031Sstas replyinCnt = reply->length; 173226031Sstas memcpy(replyin, reply->data, replyinCnt); 174226031Sstas replyout = 0; replyoutCnt = 0; 175226031Sstas kr = KERN_SUCCESS; 176226031Sstas } else { 177226031Sstas replyinCnt = 0; 178226031Sstas kr = vm_read(mach_task_self(), 179226031Sstas (vm_address_t)reply->data, reply->length, 180226031Sstas (vm_address_t *)&replyout, &replyoutCnt); 181226031Sstas } 182226031Sstas 183226031Sstas kr = mheim_aipc_acall_reply(s->reply_port, returnvalue, 184226031Sstas replyin, replyinCnt, 185226031Sstas replyout, replyoutCnt); 186226031Sstas heim_ipc_free_cred(s->cred); 187226031Sstas free(s->req.data); 188226031Sstas free(s); 189226031Sstas restart_timer(); 190226031Sstas} 191226031Sstas 192226031Sstas 193226031Sstaskern_return_t 194226031Sstasmheim_do_call(mach_port_t server_port, 195226031Sstas audit_token_t client_creds, 196226031Sstas mach_port_t reply_port, 197226031Sstas heim_ipc_message_inband_t requestin, 198226031Sstas mach_msg_type_number_t requestinCnt, 199226031Sstas heim_ipc_message_outband_t requestout, 200226031Sstas mach_msg_type_number_t requestoutCnt, 201226031Sstas int *returnvalue, 202226031Sstas heim_ipc_message_inband_t replyin, 203226031Sstas mach_msg_type_number_t *replyinCnt, 204226031Sstas heim_ipc_message_outband_t *replyout, 205226031Sstas mach_msg_type_number_t *replyoutCnt) 206226031Sstas{ 207226031Sstas heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); 208226031Sstas struct mach_call_ctx *s; 209226031Sstas kern_return_t kr; 210226031Sstas uid_t uid; 211226031Sstas gid_t gid; 212226031Sstas pid_t pid; 213226031Sstas au_asid_t session; 214226031Sstas 215226031Sstas *replyout = NULL; 216226031Sstas *replyoutCnt = 0; 217226031Sstas *replyinCnt = 0; 218226031Sstas 219226031Sstas s = malloc(sizeof(*s)); 220226031Sstas if (s == NULL) 221226031Sstas return KERN_MEMORY_FAILURE; /* XXX */ 222226031Sstas 223226031Sstas s->reply_port = reply_port; 224226031Sstas 225226031Sstas audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); 226226031Sstas 227226031Sstas kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); 228226031Sstas if (kr) { 229226031Sstas free(s); 230226031Sstas return kr; 231226031Sstas } 232226031Sstas 233226031Sstas suspend_timer(); 234226031Sstas 235226031Sstas if (requestinCnt) { 236226031Sstas s->req.data = malloc(requestinCnt); 237226031Sstas memcpy(s->req.data, requestin, requestinCnt); 238226031Sstas s->req.length = requestinCnt; 239226031Sstas } else { 240226031Sstas s->req.data = malloc(requestoutCnt); 241226031Sstas memcpy(s->req.data, requestout, requestoutCnt); 242226031Sstas s->req.length = requestoutCnt; 243226031Sstas } 244226031Sstas 245226031Sstas dispatch_async(workq, ^{ 246226031Sstas (ctx->callback)(ctx->userctx, &s->req, s->cred, 247226031Sstas mach_complete_sync, (heim_sipc_call)s); 248226031Sstas }); 249226031Sstas 250226031Sstas return MIG_NO_REPLY; 251226031Sstas} 252226031Sstas 253226031Sstaskern_return_t 254226031Sstasmheim_do_call_request(mach_port_t server_port, 255226031Sstas audit_token_t client_creds, 256226031Sstas mach_port_t reply_port, 257226031Sstas heim_ipc_message_inband_t requestin, 258226031Sstas mach_msg_type_number_t requestinCnt, 259226031Sstas heim_ipc_message_outband_t requestout, 260226031Sstas mach_msg_type_number_t requestoutCnt) 261226031Sstas{ 262226031Sstas heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); 263226031Sstas struct mach_call_ctx *s; 264226031Sstas kern_return_t kr; 265226031Sstas uid_t uid; 266226031Sstas gid_t gid; 267226031Sstas pid_t pid; 268226031Sstas au_asid_t session; 269226031Sstas 270226031Sstas s = malloc(sizeof(*s)); 271226031Sstas if (s == NULL) 272226031Sstas return KERN_MEMORY_FAILURE; /* XXX */ 273226031Sstas 274226031Sstas s->reply_port = reply_port; 275226031Sstas 276226031Sstas audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); 277226031Sstas 278226031Sstas kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); 279226031Sstas if (kr) { 280226031Sstas free(s); 281226031Sstas return kr; 282226031Sstas } 283226031Sstas 284226031Sstas suspend_timer(); 285226031Sstas 286226031Sstas if (requestinCnt) { 287226031Sstas s->req.data = malloc(requestinCnt); 288226031Sstas memcpy(s->req.data, requestin, requestinCnt); 289226031Sstas s->req.length = requestinCnt; 290226031Sstas } else { 291226031Sstas s->req.data = malloc(requestoutCnt); 292226031Sstas memcpy(s->req.data, requestout, requestoutCnt); 293226031Sstas s->req.length = requestoutCnt; 294226031Sstas } 295226031Sstas 296226031Sstas dispatch_async(workq, ^{ 297226031Sstas (ctx->callback)(ctx->userctx, &s->req, s->cred, 298226031Sstas mach_complete_async, (heim_sipc_call)s); 299226031Sstas }); 300226031Sstas 301226031Sstas return KERN_SUCCESS; 302226031Sstas} 303226031Sstas 304226031Sstasstatic int 305226031Sstasmach_init(const char *service, mach_port_t sport, heim_sipc ctx) 306226031Sstas{ 307226031Sstas struct mach_service *s; 308226031Sstas char *name; 309226031Sstas 310226031Sstas init_globals(); 311226031Sstas 312226031Sstas s = calloc(1, sizeof(*s)); 313226031Sstas if (s == NULL) 314226031Sstas return ENOMEM; 315226031Sstas 316226031Sstas asprintf(&name, "heim-ipc-mach-%s", service); 317226031Sstas 318226031Sstas s->queue = dispatch_queue_create(name, NULL); 319226031Sstas free(name); 320226031Sstas s->sport = sport; 321226031Sstas 322226031Sstas s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, 323226031Sstas s->sport, 0, s->queue); 324226031Sstas if (s->source == NULL) { 325226031Sstas dispatch_release(s->queue); 326226031Sstas free(s); 327226031Sstas return ENOMEM; 328226031Sstas } 329226031Sstas ctx->mech = s; 330226031Sstas 331226031Sstas dispatch_set_context(s->queue, ctx); 332226031Sstas dispatch_set_context(s->source, s); 333226031Sstas 334226031Sstas dispatch_source_set_event_handler(s->source, ^{ 335226031Sstas dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server); 336226031Sstas }); 337226031Sstas 338226031Sstas dispatch_source_set_cancel_handler(s->source, ^{ 339226031Sstas heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); 340226031Sstas struct mach_service *st = ctx->mech; 341226031Sstas mach_port_mod_refs(mach_task_self(), st->sport, 342226031Sstas MACH_PORT_RIGHT_RECEIVE, -1); 343226031Sstas dispatch_release(st->queue); 344226031Sstas dispatch_release(st->source); 345226031Sstas free(st); 346226031Sstas free(ctx); 347226031Sstas }); 348226031Sstas 349226031Sstas dispatch_resume(s->source); 350226031Sstas 351226031Sstas return 0; 352226031Sstas} 353226031Sstas 354226031Sstasstatic int 355226031Sstasmach_release(heim_sipc ctx) 356226031Sstas{ 357226031Sstas struct mach_service *s = ctx->mech; 358226031Sstas dispatch_source_cancel(s->source); 359226031Sstas dispatch_release(s->source); 360226031Sstas return 0; 361226031Sstas} 362226031Sstas 363226031Sstasstatic mach_port_t 364226031Sstasmach_checkin_or_register(const char *service) 365226031Sstas{ 366226031Sstas mach_port_t mp; 367226031Sstas kern_return_t kr; 368226031Sstas 369226031Sstas kr = bootstrap_check_in(bootstrap_port, service, &mp); 370226031Sstas if (kr == KERN_SUCCESS) 371226031Sstas return mp; 372226031Sstas 373226031Sstas#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 374226031Sstas /* Pre SnowLeopard version */ 375226031Sstas kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); 376226031Sstas if (kr != KERN_SUCCESS) 377226031Sstas return MACH_PORT_NULL; 378226031Sstas 379226031Sstas kr = mach_port_insert_right(mach_task_self(), mp, mp, 380226031Sstas MACH_MSG_TYPE_MAKE_SEND); 381226031Sstas if (kr != KERN_SUCCESS) { 382226031Sstas mach_port_destroy(mach_task_self(), mp); 383226031Sstas return MACH_PORT_NULL; 384226031Sstas } 385226031Sstas 386226031Sstas kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp); 387226031Sstas if (kr != KERN_SUCCESS) { 388226031Sstas mach_port_destroy(mach_task_self(), mp); 389226031Sstas return MACH_PORT_NULL; 390226031Sstas } 391226031Sstas 392226031Sstas return mp; 393226031Sstas#else 394226031Sstas return MACH_PORT_NULL; 395226031Sstas#endif 396226031Sstas} 397226031Sstas 398226031Sstas 399226031Sstas#endif /* __APPLE__ && HAVE_GCD */ 400226031Sstas 401226031Sstas 402226031Sstasint 403226031Sstasheim_sipc_launchd_mach_init(const char *service, 404226031Sstas heim_ipc_callback callback, 405226031Sstas void *user, heim_sipc *ctx) 406226031Sstas{ 407226031Sstas#if defined(__APPLE__) && defined(HAVE_GCD) 408226031Sstas mach_port_t sport = MACH_PORT_NULL; 409226031Sstas heim_sipc c = NULL; 410226031Sstas int ret; 411226031Sstas 412226031Sstas *ctx = NULL; 413226031Sstas 414226031Sstas sport = mach_checkin_or_register(service); 415226031Sstas if (sport == MACH_PORT_NULL) { 416226031Sstas ret = ENOENT; 417226031Sstas goto error; 418226031Sstas } 419226031Sstas 420226031Sstas c = calloc(1, sizeof(*c)); 421226031Sstas if (c == NULL) { 422226031Sstas ret = ENOMEM; 423226031Sstas goto error; 424226031Sstas } 425226031Sstas c->release = mach_release; 426226031Sstas c->userctx = user; 427226031Sstas c->callback = callback; 428226031Sstas 429226031Sstas ret = mach_init(service, sport, c); 430226031Sstas if (ret) 431226031Sstas goto error; 432226031Sstas 433226031Sstas *ctx = c; 434226031Sstas return 0; 435226031Sstas error: 436226031Sstas if (c) 437226031Sstas free(c); 438226031Sstas if (sport != MACH_PORT_NULL) 439226031Sstas mach_port_mod_refs(mach_task_self(), sport, 440226031Sstas MACH_PORT_RIGHT_RECEIVE, -1); 441226031Sstas return ret; 442226031Sstas#else /* !(__APPLE__ && HAVE_GCD) */ 443226031Sstas *ctx = NULL; 444226031Sstas return EINVAL; 445226031Sstas#endif /* __APPLE__ && HAVE_GCD */ 446226031Sstas} 447226031Sstas 448226031Sstasstruct client { 449226031Sstas int fd; 450226031Sstas heim_ipc_callback callback; 451226031Sstas void *userctx; 452226031Sstas int flags; 453226031Sstas#define LISTEN_SOCKET 1 454226031Sstas#define WAITING_READ 2 455226031Sstas#define WAITING_WRITE 4 456226031Sstas#define WAITING_CLOSE 8 457226031Sstas 458226031Sstas#define HTTP_REPLY 16 459226031Sstas 460226031Sstas#define INHERIT_MASK 0xffff0000 461226031Sstas#define INCLUDE_ERROR_CODE (1 << 16) 462226031Sstas#define ALLOW_HTTP (1<<17) 463226031Sstas#define UNIX_SOCKET (1<<18) 464226031Sstas unsigned calls; 465226031Sstas size_t ptr, len; 466226031Sstas uint8_t *inmsg; 467226031Sstas size_t olen; 468226031Sstas uint8_t *outmsg; 469226031Sstas#ifdef HAVE_GCD 470226031Sstas dispatch_source_t in; 471226031Sstas dispatch_source_t out; 472226031Sstas#endif 473226031Sstas struct { 474226031Sstas uid_t uid; 475226031Sstas gid_t gid; 476226031Sstas pid_t pid; 477226031Sstas } unixrights; 478226031Sstas}; 479226031Sstas 480226031Sstas#ifndef HAVE_GCD 481226031Sstasstatic unsigned num_clients = 0; 482226031Sstasstatic struct client **clients = NULL; 483226031Sstas#endif 484226031Sstas 485226031Sstasstatic void handle_read(struct client *); 486226031Sstasstatic void handle_write(struct client *); 487226031Sstasstatic int maybe_close(struct client *); 488226031Sstas 489226031Sstas/* 490226031Sstas * Update peer credentials from socket. 491226031Sstas * 492226031Sstas * SCM_CREDS can only be updated the first time there is read data to 493226031Sstas * read from the filedescriptor, so if we read do it before this 494226031Sstas * point, the cred data might not be is not there yet. 495226031Sstas */ 496226031Sstas 497226031Sstasstatic int 498226031Sstasupdate_client_creds(struct client *c) 499226031Sstas{ 500226031Sstas#ifdef HAVE_GETPEERUCRED 501226031Sstas /* Solaris 10 */ 502226031Sstas { 503226031Sstas ucred_t *peercred; 504226031Sstas 505226031Sstas if (getpeerucred(c->fd, &peercred) != 0) { 506226031Sstas c->unixrights.uid = ucred_geteuid(peercred); 507226031Sstas c->unixrights.gid = ucred_getegid(peercred); 508226031Sstas c->unixrights.pid = 0; 509226031Sstas ucred_free(peercred); 510226031Sstas return 1; 511226031Sstas } 512226031Sstas } 513226031Sstas#endif 514226031Sstas#ifdef HAVE_GETPEEREID 515226031Sstas /* FreeBSD, OpenBSD */ 516226031Sstas { 517226031Sstas uid_t uid; 518226031Sstas gid_t gid; 519226031Sstas 520226031Sstas if (getpeereid(c->fd, &uid, &gid) == 0) { 521226031Sstas c->unixrights.uid = uid; 522226031Sstas c->unixrights.gid = gid; 523226031Sstas c->unixrights.pid = 0; 524226031Sstas return 1; 525226031Sstas } 526226031Sstas } 527226031Sstas#endif 528226031Sstas#ifdef SO_PEERCRED 529226031Sstas /* Linux */ 530226031Sstas { 531226031Sstas struct ucred pc; 532226031Sstas socklen_t pclen = sizeof(pc); 533226031Sstas 534226031Sstas if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) { 535226031Sstas c->unixrights.uid = pc.uid; 536226031Sstas c->unixrights.gid = pc.gid; 537226031Sstas c->unixrights.pid = pc.pid; 538226031Sstas return 1; 539226031Sstas } 540226031Sstas } 541226031Sstas#endif 542226031Sstas#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION) 543226031Sstas { 544226031Sstas struct xucred peercred; 545226031Sstas socklen_t peercredlen = sizeof(peercred); 546226031Sstas 547226031Sstas if (getsockopt(c->fd, LOCAL_PEERCRED, 1, 548226031Sstas (void *)&peercred, &peercredlen) == 0 549226031Sstas && peercred.cr_version == XUCRED_VERSION) 550226031Sstas { 551226031Sstas c->unixrights.uid = peercred.cr_uid; 552226031Sstas c->unixrights.gid = peercred.cr_gid; 553226031Sstas c->unixrights.pid = 0; 554226031Sstas return 1; 555226031Sstas } 556226031Sstas } 557226031Sstas#endif 558226031Sstas#if defined(SOCKCREDSIZE) && defined(SCM_CREDS) 559226031Sstas /* NetBSD */ 560226031Sstas if (c->unixrights.uid == (uid_t)-1) { 561226031Sstas struct msghdr msg; 562226031Sstas socklen_t crmsgsize; 563226031Sstas void *crmsg; 564226031Sstas struct cmsghdr *cmp; 565226031Sstas struct sockcred *sc; 566226031Sstas 567226031Sstas memset(&msg, 0, sizeof(msg)); 568233294Sstas crmsgsize = CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)); 569226031Sstas if (crmsgsize == 0) 570226031Sstas return 1 ; 571226031Sstas 572226031Sstas crmsg = malloc(crmsgsize); 573226031Sstas if (crmsg == NULL) 574226031Sstas goto failed_scm_creds; 575226031Sstas 576226031Sstas memset(crmsg, 0, crmsgsize); 577226031Sstas 578226031Sstas msg.msg_control = crmsg; 579226031Sstas msg.msg_controllen = crmsgsize; 580226031Sstas 581226031Sstas if (recvmsg(c->fd, &msg, 0) < 0) { 582226031Sstas free(crmsg); 583226031Sstas goto failed_scm_creds; 584226031Sstas } 585226031Sstas 586226031Sstas if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { 587226031Sstas free(crmsg); 588226031Sstas goto failed_scm_creds; 589226031Sstas } 590226031Sstas 591226031Sstas cmp = CMSG_FIRSTHDR(&msg); 592226031Sstas if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) { 593226031Sstas free(crmsg); 594226031Sstas goto failed_scm_creds; 595226031Sstas } 596226031Sstas 597226031Sstas sc = (struct sockcred *)(void *)CMSG_DATA(cmp); 598226031Sstas 599226031Sstas c->unixrights.uid = sc->sc_euid; 600226031Sstas c->unixrights.gid = sc->sc_egid; 601226031Sstas c->unixrights.pid = 0; 602226031Sstas 603226031Sstas free(crmsg); 604226031Sstas return 1; 605226031Sstas } else { 606226031Sstas /* we already got the cred, just return it */ 607226031Sstas return 1; 608226031Sstas } 609226031Sstas failed_scm_creds: 610226031Sstas#endif 611226031Sstas return 0; 612226031Sstas} 613226031Sstas 614226031Sstas 615226031Sstasstatic struct client * 616226031Sstasadd_new_socket(int fd, 617226031Sstas int flags, 618226031Sstas heim_ipc_callback callback, 619226031Sstas void *userctx) 620226031Sstas{ 621226031Sstas struct client *c; 622226031Sstas int fileflags; 623226031Sstas 624226031Sstas c = calloc(1, sizeof(*c)); 625226031Sstas if (c == NULL) 626226031Sstas return NULL; 627226031Sstas 628226031Sstas if (flags & LISTEN_SOCKET) { 629226031Sstas c->fd = fd; 630226031Sstas } else { 631226031Sstas c->fd = accept(fd, NULL, NULL); 632226031Sstas if(c->fd < 0) { 633226031Sstas free(c); 634226031Sstas return NULL; 635226031Sstas } 636226031Sstas } 637226031Sstas 638226031Sstas c->flags = flags; 639226031Sstas c->callback = callback; 640226031Sstas c->userctx = userctx; 641226031Sstas 642226031Sstas fileflags = fcntl(c->fd, F_GETFL, 0); 643226031Sstas fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK); 644226031Sstas 645226031Sstas#ifdef HAVE_GCD 646226031Sstas init_globals(); 647226031Sstas 648226031Sstas c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 649226031Sstas c->fd, 0, eventq); 650226031Sstas c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, 651226031Sstas c->fd, 0, eventq); 652226031Sstas 653226031Sstas dispatch_source_set_event_handler(c->in, ^{ 654226031Sstas int rw = (c->flags & WAITING_WRITE); 655226031Sstas handle_read(c); 656226031Sstas if (rw == 0 && (c->flags & WAITING_WRITE)) 657226031Sstas dispatch_resume(c->out); 658226031Sstas if ((c->flags & WAITING_READ) == 0) 659226031Sstas dispatch_suspend(c->in); 660226031Sstas maybe_close(c); 661226031Sstas }); 662226031Sstas dispatch_source_set_event_handler(c->out, ^{ 663226031Sstas handle_write(c); 664226031Sstas if ((c->flags & WAITING_WRITE) == 0) { 665226031Sstas dispatch_suspend(c->out); 666226031Sstas } 667226031Sstas maybe_close(c); 668226031Sstas }); 669226031Sstas 670226031Sstas dispatch_resume(c->in); 671226031Sstas#else 672226031Sstas clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1)); 673226031Sstas clients[num_clients] = c; 674226031Sstas num_clients++; 675226031Sstas#endif 676226031Sstas 677226031Sstas return c; 678226031Sstas} 679226031Sstas 680226031Sstasstatic int 681226031Sstasmaybe_close(struct client *c) 682226031Sstas{ 683226031Sstas if (c->calls != 0) 684226031Sstas return 0; 685226031Sstas if (c->flags & (WAITING_READ|WAITING_WRITE)) 686226031Sstas return 0; 687226031Sstas 688226031Sstas#ifdef HAVE_GCD 689226031Sstas dispatch_source_cancel(c->in); 690226031Sstas if ((c->flags & WAITING_READ) == 0) 691226031Sstas dispatch_resume(c->in); 692226031Sstas dispatch_release(c->in); 693226031Sstas 694226031Sstas dispatch_source_cancel(c->out); 695226031Sstas if ((c->flags & WAITING_WRITE) == 0) 696226031Sstas dispatch_resume(c->out); 697226031Sstas dispatch_release(c->out); 698226031Sstas#endif 699226031Sstas close(c->fd); /* ref count fd close */ 700226031Sstas free(c); 701226031Sstas return 1; 702226031Sstas} 703226031Sstas 704226031Sstas 705226031Sstasstruct socket_call { 706226031Sstas heim_idata in; 707226031Sstas struct client *c; 708226031Sstas heim_icred cred; 709226031Sstas}; 710226031Sstas 711226031Sstasstatic void 712226031Sstasoutput_data(struct client *c, const void *data, size_t len) 713226031Sstas{ 714226031Sstas if (c->olen + len < c->olen) 715226031Sstas abort(); 716226031Sstas c->outmsg = erealloc(c->outmsg, c->olen + len); 717226031Sstas memcpy(&c->outmsg[c->olen], data, len); 718226031Sstas c->olen += len; 719226031Sstas c->flags |= WAITING_WRITE; 720226031Sstas} 721226031Sstas 722226031Sstasstatic void 723226031Sstassocket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply) 724226031Sstas{ 725226031Sstas struct socket_call *sc = (struct socket_call *)ctx; 726226031Sstas struct client *c = sc->c; 727226031Sstas 728226031Sstas /* double complete ? */ 729226031Sstas if (c == NULL) 730226031Sstas abort(); 731226031Sstas 732226031Sstas if ((c->flags & WAITING_CLOSE) == 0) { 733226031Sstas uint32_t u32; 734226031Sstas 735226031Sstas /* length */ 736226031Sstas u32 = htonl(reply->length); 737226031Sstas output_data(c, &u32, sizeof(u32)); 738226031Sstas 739226031Sstas /* return value */ 740226031Sstas if (c->flags & INCLUDE_ERROR_CODE) { 741226031Sstas u32 = htonl(returnvalue); 742226031Sstas output_data(c, &u32, sizeof(u32)); 743226031Sstas } 744226031Sstas 745226031Sstas /* data */ 746226031Sstas output_data(c, reply->data, reply->length); 747226031Sstas 748226031Sstas /* if HTTP, close connection */ 749226031Sstas if (c->flags & HTTP_REPLY) { 750226031Sstas c->flags |= WAITING_CLOSE; 751226031Sstas c->flags &= ~WAITING_READ; 752226031Sstas } 753226031Sstas } 754226031Sstas 755226031Sstas c->calls--; 756226031Sstas if (sc->cred) 757226031Sstas heim_ipc_free_cred(sc->cred); 758226031Sstas free(sc->in.data); 759226031Sstas sc->c = NULL; /* so we can catch double complete */ 760226031Sstas free(sc); 761226031Sstas 762226031Sstas maybe_close(c); 763226031Sstas} 764226031Sstas 765226031Sstas/* remove HTTP %-quoting from buf */ 766226031Sstasstatic int 767226031Sstasde_http(char *buf) 768226031Sstas{ 769226031Sstas unsigned char *p, *q; 770226031Sstas for(p = q = (unsigned char *)buf; *p; p++, q++) { 771226031Sstas if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) { 772226031Sstas unsigned int x; 773226031Sstas if(sscanf((char *)p + 1, "%2x", &x) != 1) 774226031Sstas return -1; 775226031Sstas *q = x; 776226031Sstas p += 2; 777226031Sstas } else 778226031Sstas *q = *p; 779226031Sstas } 780226031Sstas *q = '\0'; 781226031Sstas return 0; 782226031Sstas} 783226031Sstas 784226031Sstasstatic struct socket_call * 785226031Sstashandle_http_tcp(struct client *c) 786226031Sstas{ 787226031Sstas struct socket_call *cs; 788226031Sstas char *s, *p, *t; 789226031Sstas void *data; 790226031Sstas char *proto; 791226031Sstas int len; 792226031Sstas 793226031Sstas s = (char *)c->inmsg; 794226031Sstas 795226031Sstas p = strstr(s, "\r\n"); 796226031Sstas if (p == NULL) 797226031Sstas return NULL; 798226031Sstas 799226031Sstas *p = 0; 800226031Sstas 801226031Sstas p = NULL; 802226031Sstas t = strtok_r(s, " \t", &p); 803226031Sstas if (t == NULL) 804226031Sstas return NULL; 805226031Sstas 806226031Sstas t = strtok_r(NULL, " \t", &p); 807226031Sstas if (t == NULL) 808226031Sstas return NULL; 809226031Sstas 810226031Sstas data = malloc(strlen(t)); 811226031Sstas if (data == NULL) 812226031Sstas return NULL; 813226031Sstas 814226031Sstas if(*t == '/') 815226031Sstas t++; 816226031Sstas if(de_http(t) != 0) { 817226031Sstas free(data); 818226031Sstas return NULL; 819226031Sstas } 820226031Sstas proto = strtok_r(NULL, " \t", &p); 821226031Sstas if (proto == NULL) { 822226031Sstas free(data); 823226031Sstas return NULL; 824226031Sstas } 825226031Sstas len = base64_decode(t, data); 826226031Sstas if(len <= 0){ 827226031Sstas const char *msg = 828226031Sstas " 404 Not found\r\n" 829226031Sstas "Server: Heimdal/" VERSION "\r\n" 830226031Sstas "Cache-Control: no-cache\r\n" 831226031Sstas "Pragma: no-cache\r\n" 832226031Sstas "Content-type: text/html\r\n" 833226031Sstas "Content-transfer-encoding: 8bit\r\n\r\n" 834226031Sstas "<TITLE>404 Not found</TITLE>\r\n" 835226031Sstas "<H1>404 Not found</H1>\r\n" 836226031Sstas "That page doesn't exist, maybe you are looking for " 837226031Sstas "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n"; 838226031Sstas free(data); 839226031Sstas output_data(c, proto, strlen(proto)); 840226031Sstas output_data(c, msg, strlen(msg)); 841226031Sstas return NULL; 842226031Sstas } 843226031Sstas 844226031Sstas cs = emalloc(sizeof(*cs)); 845226031Sstas cs->c = c; 846226031Sstas cs->in.data = data; 847226031Sstas cs->in.length = len; 848226031Sstas c->ptr = 0; 849226031Sstas 850226031Sstas { 851226031Sstas const char *msg = 852226031Sstas " 200 OK\r\n" 853226031Sstas "Server: Heimdal/" VERSION "\r\n" 854226031Sstas "Cache-Control: no-cache\r\n" 855226031Sstas "Pragma: no-cache\r\n" 856226031Sstas "Content-type: application/octet-stream\r\n" 857226031Sstas "Content-transfer-encoding: binary\r\n\r\n"; 858226031Sstas output_data(c, proto, strlen(proto)); 859226031Sstas output_data(c, msg, strlen(msg)); 860226031Sstas } 861226031Sstas 862226031Sstas return cs; 863226031Sstas} 864226031Sstas 865226031Sstas 866226031Sstasstatic void 867226031Sstashandle_read(struct client *c) 868226031Sstas{ 869226031Sstas ssize_t len; 870226031Sstas uint32_t dlen; 871226031Sstas 872226031Sstas if (c->flags & LISTEN_SOCKET) { 873226031Sstas add_new_socket(c->fd, 874226031Sstas WAITING_READ | (c->flags & INHERIT_MASK), 875226031Sstas c->callback, 876226031Sstas c->userctx); 877226031Sstas return; 878226031Sstas } 879226031Sstas 880226031Sstas if (c->ptr - c->len < 1024) { 881226031Sstas c->inmsg = erealloc(c->inmsg, 882226031Sstas c->len + 1024); 883226031Sstas c->len += 1024; 884226031Sstas } 885226031Sstas 886226031Sstas len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr); 887226031Sstas if (len <= 0) { 888226031Sstas c->flags |= WAITING_CLOSE; 889226031Sstas c->flags &= ~WAITING_READ; 890226031Sstas return; 891226031Sstas } 892226031Sstas c->ptr += len; 893226031Sstas if (c->ptr > c->len) 894226031Sstas abort(); 895226031Sstas 896226031Sstas while (c->ptr >= sizeof(dlen)) { 897226031Sstas struct socket_call *cs; 898226031Sstas 899226031Sstas if((c->flags & ALLOW_HTTP) && c->ptr >= 4 && 900226031Sstas strncmp((char *)c->inmsg, "GET ", 4) == 0 && 901226031Sstas strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) { 902226031Sstas 903226031Sstas /* remove the trailing \r\n\r\n so the string is NUL terminated */ 904226031Sstas c->inmsg[c->ptr - 4] = '\0'; 905226031Sstas 906226031Sstas c->flags |= HTTP_REPLY; 907226031Sstas 908226031Sstas cs = handle_http_tcp(c); 909226031Sstas if (cs == NULL) { 910226031Sstas c->flags |= WAITING_CLOSE; 911226031Sstas c->flags &= ~WAITING_READ; 912226031Sstas break; 913226031Sstas } 914226031Sstas } else { 915226031Sstas memcpy(&dlen, c->inmsg, sizeof(dlen)); 916226031Sstas dlen = ntohl(dlen); 917226031Sstas 918226031Sstas if (dlen > MAX_PACKET_SIZE) { 919226031Sstas c->flags |= WAITING_CLOSE; 920226031Sstas c->flags &= ~WAITING_READ; 921226031Sstas return; 922226031Sstas } 923226031Sstas if (dlen > c->ptr - sizeof(dlen)) { 924226031Sstas break; 925226031Sstas } 926226031Sstas 927226031Sstas cs = emalloc(sizeof(*cs)); 928226031Sstas cs->c = c; 929226031Sstas cs->in.data = emalloc(dlen); 930226031Sstas memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen); 931226031Sstas cs->in.length = dlen; 932226031Sstas 933226031Sstas c->ptr -= sizeof(dlen) + dlen; 934226031Sstas memmove(c->inmsg, 935226031Sstas c->inmsg + sizeof(dlen) + dlen, 936226031Sstas c->ptr); 937226031Sstas } 938226031Sstas 939226031Sstas c->calls++; 940226031Sstas 941226031Sstas if ((c->flags & UNIX_SOCKET) != 0) { 942226031Sstas if (update_client_creds(c)) 943226031Sstas _heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid, 944226031Sstas c->unixrights.pid, -1, &cs->cred); 945226031Sstas } 946226031Sstas 947226031Sstas c->callback(c->userctx, &cs->in, 948226031Sstas cs->cred, socket_complete, 949226031Sstas (heim_sipc_call)cs); 950226031Sstas } 951226031Sstas} 952226031Sstas 953226031Sstasstatic void 954226031Sstashandle_write(struct client *c) 955226031Sstas{ 956226031Sstas ssize_t len; 957226031Sstas 958226031Sstas len = write(c->fd, c->outmsg, c->olen); 959226031Sstas if (len <= 0) { 960226031Sstas c->flags |= WAITING_CLOSE; 961226031Sstas c->flags &= ~(WAITING_WRITE); 962226031Sstas } else if (c->olen != (size_t)len) { 963226031Sstas memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len); 964226031Sstas c->olen -= len; 965226031Sstas } else { 966226031Sstas c->olen = 0; 967226031Sstas free(c->outmsg); 968226031Sstas c->outmsg = NULL; 969226031Sstas c->flags &= ~(WAITING_WRITE); 970226031Sstas } 971226031Sstas} 972226031Sstas 973226031Sstas 974226031Sstas#ifndef HAVE_GCD 975226031Sstas 976226031Sstasstatic void 977226031Sstasprocess_loop(void) 978226031Sstas{ 979226031Sstas struct pollfd *fds; 980226031Sstas unsigned n; 981226031Sstas unsigned num_fds; 982226031Sstas 983226031Sstas while(num_clients > 0) { 984226031Sstas 985226031Sstas fds = malloc(num_clients * sizeof(fds[0])); 986226031Sstas if(fds == NULL) 987226031Sstas abort(); 988226031Sstas 989226031Sstas num_fds = num_clients; 990226031Sstas 991226031Sstas for (n = 0 ; n < num_fds; n++) { 992226031Sstas fds[n].fd = clients[n]->fd; 993226031Sstas fds[n].events = 0; 994226031Sstas if (clients[n]->flags & WAITING_READ) 995226031Sstas fds[n].events |= POLLIN; 996226031Sstas if (clients[n]->flags & WAITING_WRITE) 997226031Sstas fds[n].events |= POLLOUT; 998226031Sstas 999226031Sstas fds[n].revents = 0; 1000226031Sstas } 1001226031Sstas 1002226031Sstas poll(fds, num_fds, -1); 1003226031Sstas 1004226031Sstas for (n = 0 ; n < num_fds; n++) { 1005226031Sstas if (clients[n] == NULL) 1006226031Sstas continue; 1007226031Sstas if (fds[n].revents & POLLERR) { 1008226031Sstas clients[n]->flags |= WAITING_CLOSE; 1009226031Sstas continue; 1010226031Sstas } 1011226031Sstas 1012226031Sstas if (fds[n].revents & POLLIN) 1013226031Sstas handle_read(clients[n]); 1014226031Sstas if (fds[n].revents & POLLOUT) 1015226031Sstas handle_write(clients[n]); 1016226031Sstas } 1017226031Sstas 1018226031Sstas n = 0; 1019226031Sstas while (n < num_clients) { 1020226031Sstas struct client *c = clients[n]; 1021226031Sstas if (maybe_close(c)) { 1022226031Sstas if (n < num_clients - 1) 1023226031Sstas clients[n] = clients[num_clients - 1]; 1024226031Sstas num_clients--; 1025226031Sstas } else 1026226031Sstas n++; 1027226031Sstas } 1028226031Sstas 1029226031Sstas free(fds); 1030226031Sstas } 1031226031Sstas} 1032226031Sstas 1033226031Sstas#endif 1034226031Sstas 1035226031Sstasstatic int 1036226031Sstassocket_release(heim_sipc ctx) 1037226031Sstas{ 1038226031Sstas struct client *c = ctx->mech; 1039226031Sstas c->flags |= WAITING_CLOSE; 1040226031Sstas return 0; 1041226031Sstas} 1042226031Sstas 1043226031Sstasint 1044226031Sstasheim_sipc_stream_listener(int fd, int type, 1045226031Sstas heim_ipc_callback callback, 1046226031Sstas void *user, heim_sipc *ctx) 1047226031Sstas{ 1048226031Sstas heim_sipc ct = calloc(1, sizeof(*ct)); 1049226031Sstas struct client *c; 1050226031Sstas 1051226031Sstas if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP))) 1052226031Sstas return EINVAL; 1053226031Sstas 1054226031Sstas switch (type) { 1055226031Sstas case HEIM_SIPC_TYPE_IPC: 1056226031Sstas c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user); 1057226031Sstas break; 1058226031Sstas case HEIM_SIPC_TYPE_UINT32: 1059226031Sstas c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user); 1060226031Sstas break; 1061226031Sstas case HEIM_SIPC_TYPE_HTTP: 1062226031Sstas case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP: 1063226031Sstas c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user); 1064226031Sstas break; 1065226031Sstas default: 1066226031Sstas free(ct); 1067226031Sstas return EINVAL; 1068226031Sstas } 1069226031Sstas 1070226031Sstas ct->mech = c; 1071226031Sstas ct->release = socket_release; 1072226031Sstas 1073226031Sstas c->unixrights.uid = (uid_t) -1; 1074226031Sstas c->unixrights.gid = (gid_t) -1; 1075226031Sstas c->unixrights.pid = (pid_t) 0; 1076226031Sstas 1077226031Sstas *ctx = ct; 1078226031Sstas return 0; 1079226031Sstas} 1080226031Sstas 1081226031Sstasint 1082226031Sstasheim_sipc_service_unix(const char *service, 1083226031Sstas heim_ipc_callback callback, 1084226031Sstas void *user, heim_sipc *ctx) 1085226031Sstas{ 1086226031Sstas struct sockaddr_un un; 1087226031Sstas int fd, ret; 1088226031Sstas 1089226031Sstas un.sun_family = AF_UNIX; 1090226031Sstas 1091226031Sstas snprintf(un.sun_path, sizeof(un.sun_path), 1092226031Sstas "/var/run/.heim_%s-socket", service); 1093226031Sstas fd = socket(AF_UNIX, SOCK_STREAM, 0); 1094226031Sstas if (fd < 0) 1095226031Sstas return errno; 1096226031Sstas 1097226031Sstas socket_set_reuseaddr(fd, 1); 1098226031Sstas#ifdef LOCAL_CREDS 1099226031Sstas { 1100226031Sstas int one = 1; 1101226031Sstas setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); 1102226031Sstas } 1103226031Sstas#endif 1104226031Sstas 1105226031Sstas unlink(un.sun_path); 1106226031Sstas 1107226031Sstas if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 1108226031Sstas close(fd); 1109226031Sstas return errno; 1110226031Sstas } 1111226031Sstas 1112226031Sstas if (listen(fd, SOMAXCONN) < 0) { 1113226031Sstas close(fd); 1114226031Sstas return errno; 1115226031Sstas } 1116226031Sstas 1117226031Sstas chmod(un.sun_path, 0666); 1118226031Sstas 1119226031Sstas ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC, 1120226031Sstas callback, user, ctx); 1121226031Sstas if (ret == 0) { 1122226031Sstas struct client *c = (*ctx)->mech; 1123226031Sstas c->flags |= UNIX_SOCKET; 1124226031Sstas } 1125226031Sstas 1126226031Sstas return ret; 1127226031Sstas} 1128226031Sstas 1129226031Sstas/** 1130226031Sstas * Set the idle timeout value 1131226031Sstas 1132226031Sstas * The timeout event handler is triggered recurrently every idle 1133226031Sstas * period `t'. The default action is rather draconian and just calls 1134226031Sstas * exit(0), so you might want to change this to something more 1135226031Sstas * graceful using heim_sipc_set_timeout_handler(). 1136226031Sstas */ 1137226031Sstas 1138226031Sstasvoid 1139226031Sstasheim_sipc_timeout(time_t t) 1140226031Sstas{ 1141226031Sstas#ifdef HAVE_GCD 1142226031Sstas static dispatch_once_t timeoutonce; 1143226031Sstas init_globals(); 1144226031Sstas dispatch_sync(timerq, ^{ 1145226031Sstas timeoutvalue = t; 1146226031Sstas set_timer(); 1147226031Sstas }); 1148226031Sstas dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); }); 1149226031Sstas#else 1150226031Sstas abort(); 1151226031Sstas#endif 1152226031Sstas} 1153226031Sstas 1154226031Sstas/** 1155226031Sstas * Set the timeout event handler 1156226031Sstas * 1157226031Sstas * Replaces the default idle timeout action. 1158226031Sstas */ 1159226031Sstas 1160226031Sstasvoid 1161226031Sstasheim_sipc_set_timeout_handler(void (*func)(void)) 1162226031Sstas{ 1163226031Sstas#ifdef HAVE_GCD 1164226031Sstas init_globals(); 1165226031Sstas dispatch_sync(timerq, ^{ timer_ev = func; }); 1166226031Sstas#else 1167226031Sstas abort(); 1168226031Sstas#endif 1169226031Sstas} 1170226031Sstas 1171226031Sstas 1172226031Sstasvoid 1173226031Sstasheim_sipc_free_context(heim_sipc ctx) 1174226031Sstas{ 1175226031Sstas (ctx->release)(ctx); 1176226031Sstas} 1177226031Sstas 1178226031Sstasvoid 1179226031Sstasheim_ipc_main(void) 1180226031Sstas{ 1181226031Sstas#ifdef HAVE_GCD 1182226031Sstas dispatch_main(); 1183226031Sstas#else 1184226031Sstas process_loop(); 1185226031Sstas#endif 1186226031Sstas} 1187226031Sstas 1188