Home | History | Annotate | Line # | Download | only in ipc
server.c revision 1.1.1.2.12.1
      1  1.1.1.2.12.1     snj /*	$NetBSD: server.c,v 1.1.1.2.12.1 2017/08/20 05:44:20 snj Exp $	*/
      2           1.1   elric 
      3           1.1   elric /*
      4           1.1   elric  * Copyright (c) 2009 Kungliga Tekniska Hgskolan
      5           1.1   elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6           1.1   elric  * All rights reserved.
      7           1.1   elric  *
      8           1.1   elric  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
      9           1.1   elric  *
     10           1.1   elric  * Redistribution and use in source and binary forms, with or without
     11           1.1   elric  * modification, are permitted provided that the following conditions
     12           1.1   elric  * are met:
     13           1.1   elric  *
     14           1.1   elric  * 1. Redistributions of source code must retain the above copyright
     15           1.1   elric  *    notice, this list of conditions and the following disclaimer.
     16           1.1   elric  *
     17           1.1   elric  * 2. Redistributions in binary form must reproduce the above copyright
     18           1.1   elric  *    notice, this list of conditions and the following disclaimer in the
     19           1.1   elric  *    documentation and/or other materials provided with the distribution.
     20           1.1   elric  *
     21           1.1   elric  * 3. Neither the name of the Institute nor the names of its contributors
     22           1.1   elric  *    may be used to endorse or promote products derived from this software
     23           1.1   elric  *    without specific prior written permission.
     24           1.1   elric  *
     25           1.1   elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     26           1.1   elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27           1.1   elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28           1.1   elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     29           1.1   elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30           1.1   elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31           1.1   elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32           1.1   elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33           1.1   elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34           1.1   elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35           1.1   elric  * SUCH DAMAGE.
     36           1.1   elric  */
     37           1.1   elric 
     38           1.1   elric #include "hi_locl.h"
     39           1.1   elric #include <assert.h>
     40  1.1.1.2.12.1     snj #include <err.h>
     41           1.1   elric 
     42           1.1   elric #define MAX_PACKET_SIZE (128 * 1024)
     43           1.1   elric 
     44           1.1   elric struct heim_sipc {
     45           1.1   elric     int (*release)(heim_sipc ctx);
     46           1.1   elric     heim_ipc_callback callback;
     47           1.1   elric     void *userctx;
     48           1.1   elric     void *mech;
     49           1.1   elric };
     50           1.1   elric 
     51           1.1   elric #if defined(__APPLE__) && defined(HAVE_GCD)
     52           1.1   elric 
     53           1.1   elric #include "heim_ipcServer.h"
     54           1.1   elric #include "heim_ipc_reply.h"
     55           1.1   elric #include "heim_ipc_async.h"
     56           1.1   elric 
     57           1.1   elric static dispatch_source_t timer;
     58           1.1   elric static dispatch_queue_t timerq;
     59           1.1   elric static uint64_t timeoutvalue;
     60           1.1   elric 
     61           1.1   elric static dispatch_queue_t eventq;
     62           1.1   elric 
     63           1.1   elric static dispatch_queue_t workq;
     64           1.1   elric 
     65           1.1   elric static void
     66           1.1   elric default_timer_ev(void)
     67           1.1   elric {
     68           1.1   elric     exit(0);
     69           1.1   elric }
     70           1.1   elric 
     71           1.1   elric static void (*timer_ev)(void) = default_timer_ev;
     72           1.1   elric 
     73           1.1   elric static void
     74           1.1   elric set_timer(void)
     75           1.1   elric {
     76           1.1   elric     dispatch_source_set_timer(timer,
     77           1.1   elric 			      dispatch_time(DISPATCH_TIME_NOW,
     78           1.1   elric 					    timeoutvalue * NSEC_PER_SEC),
     79       1.1.1.2  pettai 			      timeoutvalue * NSEC_PER_SEC, 1000000);
     80           1.1   elric }
     81           1.1   elric 
     82           1.1   elric static void
     83           1.1   elric init_globals(void)
     84           1.1   elric {
     85           1.1   elric     static dispatch_once_t once;
     86       1.1.1.2  pettai     dispatch_once(&once, ^{
     87           1.1   elric 	timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL);
     88           1.1   elric         timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq);
     89           1.1   elric 	dispatch_source_set_event_handler(timer, ^{ timer_ev(); } );
     90           1.1   elric 
     91           1.1   elric 	workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     92           1.1   elric 	eventq = dispatch_queue_create("heim-ipc.event-queue", NULL);
     93           1.1   elric     });
     94           1.1   elric }
     95           1.1   elric 
     96           1.1   elric static void
     97           1.1   elric suspend_timer(void)
     98           1.1   elric {
     99           1.1   elric     dispatch_suspend(timer);
    100           1.1   elric }
    101           1.1   elric 
    102           1.1   elric static void
    103           1.1   elric restart_timer(void)
    104           1.1   elric {
    105           1.1   elric     dispatch_sync(timerq, ^{ set_timer(); });
    106           1.1   elric     dispatch_resume(timer);
    107           1.1   elric }
    108           1.1   elric 
    109           1.1   elric struct mach_service {
    110           1.1   elric     mach_port_t sport;
    111           1.1   elric     dispatch_source_t source;
    112           1.1   elric     dispatch_queue_t queue;
    113           1.1   elric };
    114           1.1   elric 
    115           1.1   elric struct mach_call_ctx {
    116           1.1   elric     mach_port_t reply_port;
    117           1.1   elric     heim_icred cred;
    118           1.1   elric     heim_idata req;
    119           1.1   elric };
    120           1.1   elric 
    121           1.1   elric 
    122           1.1   elric static void
    123           1.1   elric mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
    124           1.1   elric {
    125           1.1   elric     struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
    126           1.1   elric     heim_ipc_message_inband_t replyin;
    127           1.1   elric     mach_msg_type_number_t replyinCnt;
    128           1.1   elric     heim_ipc_message_outband_t replyout;
    129           1.1   elric     mach_msg_type_number_t replyoutCnt;
    130           1.1   elric     kern_return_t kr;
    131           1.1   elric 
    132           1.1   elric     if (returnvalue) {
    133           1.1   elric 	/* on error, no reply */
    134           1.1   elric 	replyinCnt = 0;
    135           1.1   elric 	replyout = 0; replyoutCnt = 0;
    136           1.1   elric 	kr = KERN_SUCCESS;
    137           1.1   elric     } else if (reply->length < 2048) {
    138           1.1   elric 	replyinCnt = reply->length;
    139           1.1   elric 	memcpy(replyin, reply->data, replyinCnt);
    140           1.1   elric 	replyout = 0; replyoutCnt = 0;
    141           1.1   elric 	kr = KERN_SUCCESS;
    142           1.1   elric     } else {
    143           1.1   elric 	replyinCnt = 0;
    144       1.1.1.2  pettai 	kr = vm_read(mach_task_self(),
    145           1.1   elric 		     (vm_address_t)reply->data, reply->length,
    146           1.1   elric 		     (vm_address_t *)&replyout, &replyoutCnt);
    147           1.1   elric     }
    148           1.1   elric 
    149           1.1   elric     mheim_ripc_call_reply(s->reply_port, returnvalue,
    150           1.1   elric 			  replyin, replyinCnt,
    151           1.1   elric 			  replyout, replyoutCnt);
    152           1.1   elric 
    153           1.1   elric     heim_ipc_free_cred(s->cred);
    154           1.1   elric     free(s->req.data);
    155           1.1   elric     free(s);
    156           1.1   elric     restart_timer();
    157           1.1   elric }
    158           1.1   elric 
    159           1.1   elric static void
    160           1.1   elric mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
    161           1.1   elric {
    162           1.1   elric     struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
    163           1.1   elric     heim_ipc_message_inband_t replyin;
    164           1.1   elric     mach_msg_type_number_t replyinCnt;
    165           1.1   elric     heim_ipc_message_outband_t replyout;
    166           1.1   elric     mach_msg_type_number_t replyoutCnt;
    167           1.1   elric     kern_return_t kr;
    168           1.1   elric 
    169           1.1   elric     if (returnvalue) {
    170           1.1   elric 	/* on error, no reply */
    171           1.1   elric 	replyinCnt = 0;
    172           1.1   elric 	replyout = 0; replyoutCnt = 0;
    173           1.1   elric 	kr = KERN_SUCCESS;
    174           1.1   elric     } else if (reply->length < 2048) {
    175           1.1   elric 	replyinCnt = reply->length;
    176           1.1   elric 	memcpy(replyin, reply->data, replyinCnt);
    177           1.1   elric 	replyout = 0; replyoutCnt = 0;
    178           1.1   elric 	kr = KERN_SUCCESS;
    179           1.1   elric     } else {
    180           1.1   elric 	replyinCnt = 0;
    181       1.1.1.2  pettai 	kr = vm_read(mach_task_self(),
    182           1.1   elric 		     (vm_address_t)reply->data, reply->length,
    183           1.1   elric 		     (vm_address_t *)&replyout, &replyoutCnt);
    184           1.1   elric     }
    185           1.1   elric 
    186           1.1   elric     kr = mheim_aipc_acall_reply(s->reply_port, returnvalue,
    187           1.1   elric 				replyin, replyinCnt,
    188           1.1   elric 				replyout, replyoutCnt);
    189           1.1   elric     heim_ipc_free_cred(s->cred);
    190           1.1   elric     free(s->req.data);
    191           1.1   elric     free(s);
    192           1.1   elric     restart_timer();
    193           1.1   elric }
    194           1.1   elric 
    195           1.1   elric 
    196           1.1   elric kern_return_t
    197           1.1   elric mheim_do_call(mach_port_t server_port,
    198           1.1   elric 	      audit_token_t client_creds,
    199           1.1   elric 	      mach_port_t reply_port,
    200           1.1   elric 	      heim_ipc_message_inband_t requestin,
    201           1.1   elric 	      mach_msg_type_number_t requestinCnt,
    202           1.1   elric 	      heim_ipc_message_outband_t requestout,
    203           1.1   elric 	      mach_msg_type_number_t requestoutCnt,
    204           1.1   elric 	      int *returnvalue,
    205           1.1   elric 	      heim_ipc_message_inband_t replyin,
    206           1.1   elric 	      mach_msg_type_number_t *replyinCnt,
    207           1.1   elric 	      heim_ipc_message_outband_t *replyout,
    208           1.1   elric 	      mach_msg_type_number_t *replyoutCnt)
    209           1.1   elric {
    210           1.1   elric     heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
    211           1.1   elric     struct mach_call_ctx *s;
    212           1.1   elric     kern_return_t kr;
    213           1.1   elric     uid_t uid;
    214           1.1   elric     gid_t gid;
    215           1.1   elric     pid_t pid;
    216           1.1   elric     au_asid_t session;
    217           1.1   elric 
    218           1.1   elric     *replyout = NULL;
    219           1.1   elric     *replyoutCnt = 0;
    220           1.1   elric     *replyinCnt = 0;
    221           1.1   elric 
    222           1.1   elric     s = malloc(sizeof(*s));
    223           1.1   elric     if (s == NULL)
    224           1.1   elric 	return KERN_MEMORY_FAILURE; /* XXX */
    225       1.1.1.2  pettai 
    226           1.1   elric     s->reply_port = reply_port;
    227       1.1.1.2  pettai 
    228           1.1   elric     audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
    229       1.1.1.2  pettai 
    230           1.1   elric     kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
    231           1.1   elric     if (kr) {
    232           1.1   elric 	free(s);
    233           1.1   elric 	return kr;
    234           1.1   elric     }
    235       1.1.1.2  pettai 
    236           1.1   elric     suspend_timer();
    237       1.1.1.2  pettai 
    238           1.1   elric     if (requestinCnt) {
    239           1.1   elric 	s->req.data = malloc(requestinCnt);
    240           1.1   elric 	memcpy(s->req.data, requestin, requestinCnt);
    241           1.1   elric 	s->req.length = requestinCnt;
    242           1.1   elric     } else {
    243           1.1   elric 	s->req.data = malloc(requestoutCnt);
    244           1.1   elric 	memcpy(s->req.data, requestout, requestoutCnt);
    245           1.1   elric 	s->req.length = requestoutCnt;
    246           1.1   elric     }
    247       1.1.1.2  pettai 
    248           1.1   elric     dispatch_async(workq, ^{
    249           1.1   elric 	(ctx->callback)(ctx->userctx, &s->req, s->cred,
    250           1.1   elric 			mach_complete_sync, (heim_sipc_call)s);
    251           1.1   elric     });
    252           1.1   elric 
    253           1.1   elric     return MIG_NO_REPLY;
    254           1.1   elric }
    255           1.1   elric 
    256           1.1   elric kern_return_t
    257           1.1   elric mheim_do_call_request(mach_port_t server_port,
    258           1.1   elric 		      audit_token_t client_creds,
    259           1.1   elric 		      mach_port_t reply_port,
    260           1.1   elric 		      heim_ipc_message_inband_t requestin,
    261           1.1   elric 		      mach_msg_type_number_t requestinCnt,
    262           1.1   elric 		      heim_ipc_message_outband_t requestout,
    263           1.1   elric 		      mach_msg_type_number_t requestoutCnt)
    264           1.1   elric {
    265           1.1   elric     heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
    266           1.1   elric     struct mach_call_ctx *s;
    267           1.1   elric     kern_return_t kr;
    268           1.1   elric     uid_t uid;
    269           1.1   elric     gid_t gid;
    270           1.1   elric     pid_t pid;
    271           1.1   elric     au_asid_t session;
    272       1.1.1.2  pettai 
    273           1.1   elric     s = malloc(sizeof(*s));
    274           1.1   elric     if (s == NULL)
    275           1.1   elric 	return KERN_MEMORY_FAILURE; /* XXX */
    276       1.1.1.2  pettai 
    277           1.1   elric     s->reply_port = reply_port;
    278       1.1.1.2  pettai 
    279           1.1   elric     audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
    280       1.1.1.2  pettai 
    281           1.1   elric     kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
    282           1.1   elric     if (kr) {
    283           1.1   elric 	free(s);
    284           1.1   elric 	return kr;
    285           1.1   elric     }
    286       1.1.1.2  pettai 
    287           1.1   elric     suspend_timer();
    288       1.1.1.2  pettai 
    289           1.1   elric     if (requestinCnt) {
    290           1.1   elric 	s->req.data = malloc(requestinCnt);
    291           1.1   elric 	memcpy(s->req.data, requestin, requestinCnt);
    292           1.1   elric 	s->req.length = requestinCnt;
    293           1.1   elric     } else {
    294           1.1   elric 	s->req.data = malloc(requestoutCnt);
    295           1.1   elric 	memcpy(s->req.data, requestout, requestoutCnt);
    296           1.1   elric 	s->req.length = requestoutCnt;
    297           1.1   elric     }
    298       1.1.1.2  pettai 
    299           1.1   elric     dispatch_async(workq, ^{
    300           1.1   elric 	(ctx->callback)(ctx->userctx, &s->req, s->cred,
    301           1.1   elric 			mach_complete_async, (heim_sipc_call)s);
    302           1.1   elric     });
    303       1.1.1.2  pettai 
    304           1.1   elric     return KERN_SUCCESS;
    305           1.1   elric }
    306           1.1   elric 
    307           1.1   elric static int
    308           1.1   elric mach_init(const char *service, mach_port_t sport, heim_sipc ctx)
    309           1.1   elric {
    310           1.1   elric     struct mach_service *s;
    311           1.1   elric     char *name;
    312           1.1   elric 
    313           1.1   elric     init_globals();
    314           1.1   elric 
    315           1.1   elric     s = calloc(1, sizeof(*s));
    316           1.1   elric     if (s == NULL)
    317           1.1   elric 	return ENOMEM;
    318           1.1   elric 
    319           1.1   elric     asprintf(&name, "heim-ipc-mach-%s", service);
    320           1.1   elric 
    321           1.1   elric     s->queue = dispatch_queue_create(name, NULL);
    322           1.1   elric     free(name);
    323           1.1   elric     s->sport = sport;
    324           1.1   elric 
    325       1.1.1.2  pettai     s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
    326           1.1   elric 				       s->sport, 0, s->queue);
    327           1.1   elric     if (s->source == NULL) {
    328           1.1   elric 	dispatch_release(s->queue);
    329           1.1   elric 	free(s);
    330           1.1   elric 	return ENOMEM;
    331           1.1   elric     }
    332           1.1   elric     ctx->mech = s;
    333           1.1   elric 
    334           1.1   elric     dispatch_set_context(s->queue, ctx);
    335           1.1   elric     dispatch_set_context(s->source, s);
    336           1.1   elric 
    337           1.1   elric     dispatch_source_set_event_handler(s->source, ^{
    338           1.1   elric 	    dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server);
    339           1.1   elric 	});
    340           1.1   elric 
    341           1.1   elric     dispatch_source_set_cancel_handler(s->source, ^{
    342  1.1.1.2.12.1     snj 	    heim_sipc sctx = dispatch_get_context(dispatch_get_current_queue());
    343  1.1.1.2.12.1     snj 	    struct mach_service *st = sctx->mech;
    344       1.1.1.2  pettai 	    mach_port_mod_refs(mach_task_self(), st->sport,
    345           1.1   elric 			       MACH_PORT_RIGHT_RECEIVE, -1);
    346           1.1   elric 	    dispatch_release(st->queue);
    347           1.1   elric 	    dispatch_release(st->source);
    348           1.1   elric 	    free(st);
    349  1.1.1.2.12.1     snj 	    free(sctx);
    350           1.1   elric 	});
    351           1.1   elric 
    352           1.1   elric     dispatch_resume(s->source);
    353           1.1   elric 
    354           1.1   elric     return 0;
    355           1.1   elric }
    356           1.1   elric 
    357           1.1   elric static int
    358           1.1   elric mach_release(heim_sipc ctx)
    359           1.1   elric {
    360           1.1   elric     struct mach_service *s = ctx->mech;
    361           1.1   elric     dispatch_source_cancel(s->source);
    362           1.1   elric     dispatch_release(s->source);
    363           1.1   elric     return 0;
    364           1.1   elric }
    365           1.1   elric 
    366           1.1   elric static mach_port_t
    367           1.1   elric mach_checkin_or_register(const char *service)
    368           1.1   elric {
    369           1.1   elric     mach_port_t mp;
    370           1.1   elric     kern_return_t kr;
    371           1.1   elric 
    372           1.1   elric     kr = bootstrap_check_in(bootstrap_port, service, &mp);
    373           1.1   elric     if (kr == KERN_SUCCESS)
    374           1.1   elric 	return mp;
    375           1.1   elric 
    376           1.1   elric #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
    377           1.1   elric     /* Pre SnowLeopard version */
    378           1.1   elric     kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
    379           1.1   elric     if (kr != KERN_SUCCESS)
    380           1.1   elric 	return MACH_PORT_NULL;
    381           1.1   elric 
    382       1.1.1.2  pettai     kr = mach_port_insert_right(mach_task_self(), mp, mp,
    383           1.1   elric 				MACH_MSG_TYPE_MAKE_SEND);
    384           1.1   elric     if (kr != KERN_SUCCESS) {
    385           1.1   elric 	mach_port_destroy(mach_task_self(), mp);
    386           1.1   elric 	return MACH_PORT_NULL;
    387           1.1   elric     }
    388           1.1   elric 
    389           1.1   elric     kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp);
    390           1.1   elric     if (kr != KERN_SUCCESS) {
    391           1.1   elric 	mach_port_destroy(mach_task_self(), mp);
    392           1.1   elric 	return MACH_PORT_NULL;
    393           1.1   elric     }
    394           1.1   elric 
    395           1.1   elric     return mp;
    396           1.1   elric #else
    397           1.1   elric     return MACH_PORT_NULL;
    398           1.1   elric #endif
    399           1.1   elric }
    400           1.1   elric 
    401           1.1   elric 
    402           1.1   elric #endif /* __APPLE__ && HAVE_GCD */
    403           1.1   elric 
    404           1.1   elric 
    405           1.1   elric int
    406           1.1   elric heim_sipc_launchd_mach_init(const char *service,
    407           1.1   elric 			    heim_ipc_callback callback,
    408           1.1   elric 			    void *user, heim_sipc *ctx)
    409           1.1   elric {
    410           1.1   elric #if defined(__APPLE__) && defined(HAVE_GCD)
    411           1.1   elric     mach_port_t sport = MACH_PORT_NULL;
    412           1.1   elric     heim_sipc c = NULL;
    413           1.1   elric     int ret;
    414           1.1   elric 
    415           1.1   elric     *ctx = NULL;
    416           1.1   elric 
    417           1.1   elric     sport = mach_checkin_or_register(service);
    418           1.1   elric     if (sport == MACH_PORT_NULL) {
    419           1.1   elric 	ret = ENOENT;
    420           1.1   elric 	goto error;
    421           1.1   elric     }
    422           1.1   elric 
    423           1.1   elric     c = calloc(1, sizeof(*c));
    424           1.1   elric     if (c == NULL) {
    425           1.1   elric 	ret = ENOMEM;
    426           1.1   elric 	goto error;
    427           1.1   elric     }
    428           1.1   elric     c->release = mach_release;
    429           1.1   elric     c->userctx = user;
    430           1.1   elric     c->callback = callback;
    431       1.1.1.2  pettai 
    432           1.1   elric     ret = mach_init(service, sport, c);
    433           1.1   elric     if (ret)
    434           1.1   elric 	goto error;
    435           1.1   elric 
    436           1.1   elric     *ctx = c;
    437           1.1   elric     return 0;
    438           1.1   elric  error:
    439           1.1   elric     if (c)
    440           1.1   elric 	free(c);
    441           1.1   elric     if (sport != MACH_PORT_NULL)
    442       1.1.1.2  pettai 	mach_port_mod_refs(mach_task_self(), sport,
    443           1.1   elric 			   MACH_PORT_RIGHT_RECEIVE, -1);
    444           1.1   elric     return ret;
    445           1.1   elric #else /* !(__APPLE__ && HAVE_GCD) */
    446           1.1   elric     *ctx = NULL;
    447           1.1   elric     return EINVAL;
    448           1.1   elric #endif /* __APPLE__ && HAVE_GCD */
    449           1.1   elric }
    450           1.1   elric 
    451           1.1   elric struct client {
    452           1.1   elric     int fd;
    453           1.1   elric     heim_ipc_callback callback;
    454           1.1   elric     void *userctx;
    455           1.1   elric     int flags;
    456           1.1   elric #define LISTEN_SOCKET	1
    457           1.1   elric #define WAITING_READ	2
    458           1.1   elric #define WAITING_WRITE	4
    459           1.1   elric #define WAITING_CLOSE	8
    460           1.1   elric 
    461           1.1   elric #define HTTP_REPLY	16
    462           1.1   elric 
    463           1.1   elric #define INHERIT_MASK	0xffff0000
    464           1.1   elric #define INCLUDE_ERROR_CODE (1 << 16)
    465           1.1   elric #define ALLOW_HTTP	(1<<17)
    466           1.1   elric #define UNIX_SOCKET	(1<<18)
    467           1.1   elric     unsigned calls;
    468           1.1   elric     size_t ptr, len;
    469           1.1   elric     uint8_t *inmsg;
    470           1.1   elric     size_t olen;
    471           1.1   elric     uint8_t *outmsg;
    472           1.1   elric #ifdef HAVE_GCD
    473           1.1   elric     dispatch_source_t in;
    474           1.1   elric     dispatch_source_t out;
    475           1.1   elric #endif
    476           1.1   elric     struct {
    477           1.1   elric 	uid_t uid;
    478           1.1   elric 	gid_t gid;
    479           1.1   elric 	pid_t pid;
    480           1.1   elric     } unixrights;
    481           1.1   elric };
    482           1.1   elric 
    483           1.1   elric #ifndef HAVE_GCD
    484           1.1   elric static unsigned num_clients = 0;
    485           1.1   elric static struct client **clients = NULL;
    486           1.1   elric #endif
    487           1.1   elric 
    488           1.1   elric static void handle_read(struct client *);
    489           1.1   elric static void handle_write(struct client *);
    490           1.1   elric static int maybe_close(struct client *);
    491           1.1   elric 
    492           1.1   elric /*
    493           1.1   elric  * Update peer credentials from socket.
    494           1.1   elric  *
    495           1.1   elric  * SCM_CREDS can only be updated the first time there is read data to
    496           1.1   elric  * read from the filedescriptor, so if we read do it before this
    497           1.1   elric  * point, the cred data might not be is not there yet.
    498           1.1   elric  */
    499           1.1   elric 
    500           1.1   elric static int
    501           1.1   elric update_client_creds(struct client *c)
    502           1.1   elric {
    503           1.1   elric #ifdef HAVE_GETPEERUCRED
    504           1.1   elric     /* Solaris 10 */
    505           1.1   elric     {
    506           1.1   elric 	ucred_t *peercred;
    507       1.1.1.2  pettai 
    508           1.1   elric 	if (getpeerucred(c->fd, &peercred) != 0) {
    509           1.1   elric 	    c->unixrights.uid = ucred_geteuid(peercred);
    510           1.1   elric 	    c->unixrights.gid = ucred_getegid(peercred);
    511           1.1   elric 	    c->unixrights.pid = 0;
    512           1.1   elric 	    ucred_free(peercred);
    513           1.1   elric 	    return 1;
    514           1.1   elric 	}
    515           1.1   elric     }
    516           1.1   elric #endif
    517           1.1   elric #ifdef HAVE_GETPEEREID
    518           1.1   elric     /* FreeBSD, OpenBSD */
    519           1.1   elric     {
    520           1.1   elric 	uid_t uid;
    521           1.1   elric 	gid_t gid;
    522           1.1   elric 
    523           1.1   elric 	if (getpeereid(c->fd, &uid, &gid) == 0) {
    524           1.1   elric 	    c->unixrights.uid = uid;
    525           1.1   elric 	    c->unixrights.gid = gid;
    526           1.1   elric 	    c->unixrights.pid = 0;
    527           1.1   elric 	    return 1;
    528           1.1   elric 	}
    529           1.1   elric     }
    530           1.1   elric #endif
    531       1.1.1.2  pettai #if defined(SO_PEERCRED) && defined(__linux__)
    532           1.1   elric     /* Linux */
    533           1.1   elric     {
    534           1.1   elric 	struct ucred pc;
    535           1.1   elric 	socklen_t pclen = sizeof(pc);
    536           1.1   elric 
    537           1.1   elric 	if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
    538           1.1   elric 	    c->unixrights.uid = pc.uid;
    539           1.1   elric 	    c->unixrights.gid = pc.gid;
    540           1.1   elric 	    c->unixrights.pid = pc.pid;
    541           1.1   elric 	    return 1;
    542           1.1   elric 	}
    543           1.1   elric     }
    544           1.1   elric #endif
    545           1.1   elric #if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
    546           1.1   elric     {
    547           1.1   elric 	struct xucred peercred;
    548           1.1   elric 	socklen_t peercredlen = sizeof(peercred);
    549           1.1   elric 
    550           1.1   elric 	if (getsockopt(c->fd, LOCAL_PEERCRED, 1,
    551           1.1   elric 		       (void *)&peercred, &peercredlen) == 0
    552           1.1   elric 	    && peercred.cr_version == XUCRED_VERSION)
    553           1.1   elric 	{
    554           1.1   elric 	    c->unixrights.uid = peercred.cr_uid;
    555           1.1   elric 	    c->unixrights.gid = peercred.cr_gid;
    556           1.1   elric 	    c->unixrights.pid = 0;
    557           1.1   elric 	    return 1;
    558           1.1   elric 	}
    559           1.1   elric     }
    560           1.1   elric #endif
    561           1.1   elric #if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
    562           1.1   elric     /* NetBSD */
    563       1.1.1.2  pettai     if (c->unixrights.uid == (uid_t)-1) {
    564           1.1   elric 	struct msghdr msg;
    565           1.1   elric 	socklen_t crmsgsize;
    566           1.1   elric 	void *crmsg;
    567           1.1   elric 	struct cmsghdr *cmp;
    568           1.1   elric 	struct sockcred *sc;
    569       1.1.1.2  pettai 
    570           1.1   elric 	memset(&msg, 0, sizeof(msg));
    571           1.1   elric 	crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
    572           1.1   elric 	if (crmsgsize == 0)
    573           1.1   elric 	    return 1 ;
    574           1.1   elric 
    575           1.1   elric 	crmsg = malloc(crmsgsize);
    576           1.1   elric 	if (crmsg == NULL)
    577           1.1   elric 	    goto failed_scm_creds;
    578           1.1   elric 
    579           1.1   elric 	memset(crmsg, 0, crmsgsize);
    580       1.1.1.2  pettai 
    581           1.1   elric 	msg.msg_control = crmsg;
    582           1.1   elric 	msg.msg_controllen = crmsgsize;
    583       1.1.1.2  pettai 
    584           1.1   elric 	if (recvmsg(c->fd, &msg, 0) < 0) {
    585           1.1   elric 	    free(crmsg);
    586           1.1   elric 	    goto failed_scm_creds;
    587       1.1.1.2  pettai 	}
    588       1.1.1.2  pettai 
    589           1.1   elric 	if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
    590           1.1   elric 	    free(crmsg);
    591           1.1   elric 	    goto failed_scm_creds;
    592       1.1.1.2  pettai 	}
    593       1.1.1.2  pettai 
    594           1.1   elric 	cmp = CMSG_FIRSTHDR(&msg);
    595           1.1   elric 	if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
    596           1.1   elric 	    free(crmsg);
    597           1.1   elric 	    goto failed_scm_creds;
    598       1.1.1.2  pettai 	}
    599       1.1.1.2  pettai 
    600           1.1   elric 	sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
    601       1.1.1.2  pettai 
    602           1.1   elric 	c->unixrights.uid = sc->sc_euid;
    603           1.1   elric 	c->unixrights.gid = sc->sc_egid;
    604           1.1   elric 	c->unixrights.pid = 0;
    605       1.1.1.2  pettai 
    606           1.1   elric 	free(crmsg);
    607           1.1   elric 	return 1;
    608           1.1   elric     } else {
    609           1.1   elric 	/* we already got the cred, just return it */
    610           1.1   elric 	return 1;
    611           1.1   elric     }
    612           1.1   elric  failed_scm_creds:
    613           1.1   elric #endif
    614           1.1   elric     return 0;
    615           1.1   elric }
    616           1.1   elric 
    617           1.1   elric 
    618           1.1   elric static struct client *
    619           1.1   elric add_new_socket(int fd,
    620           1.1   elric 	       int flags,
    621           1.1   elric 	       heim_ipc_callback callback,
    622           1.1   elric 	       void *userctx)
    623           1.1   elric {
    624           1.1   elric     struct client *c;
    625           1.1   elric     int fileflags;
    626           1.1   elric 
    627           1.1   elric     c = calloc(1, sizeof(*c));
    628           1.1   elric     if (c == NULL)
    629           1.1   elric 	return NULL;
    630       1.1.1.2  pettai 
    631           1.1   elric     if (flags & LISTEN_SOCKET) {
    632           1.1   elric 	c->fd = fd;
    633           1.1   elric     } else {
    634           1.1   elric 	c->fd = accept(fd, NULL, NULL);
    635           1.1   elric 	if(c->fd < 0) {
    636           1.1   elric 	    free(c);
    637           1.1   elric 	    return NULL;
    638           1.1   elric 	}
    639           1.1   elric     }
    640           1.1   elric 
    641           1.1   elric     c->flags = flags;
    642           1.1   elric     c->callback = callback;
    643           1.1   elric     c->userctx = userctx;
    644           1.1   elric 
    645           1.1   elric     fileflags = fcntl(c->fd, F_GETFL, 0);
    646           1.1   elric     fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK);
    647           1.1   elric 
    648           1.1   elric #ifdef HAVE_GCD
    649           1.1   elric     init_globals();
    650       1.1.1.2  pettai 
    651       1.1.1.2  pettai     c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
    652           1.1   elric 				   c->fd, 0, eventq);
    653           1.1   elric     c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
    654           1.1   elric 				    c->fd, 0, eventq);
    655       1.1.1.2  pettai 
    656       1.1.1.2  pettai     dispatch_source_set_event_handler(c->in, ^{
    657           1.1   elric 	    int rw = (c->flags & WAITING_WRITE);
    658           1.1   elric 	    handle_read(c);
    659           1.1   elric 	    if (rw == 0 && (c->flags & WAITING_WRITE))
    660           1.1   elric 		dispatch_resume(c->out);
    661           1.1   elric 	    if ((c->flags & WAITING_READ) == 0)
    662           1.1   elric 		dispatch_suspend(c->in);
    663           1.1   elric 	    maybe_close(c);
    664           1.1   elric 	});
    665           1.1   elric     dispatch_source_set_event_handler(c->out, ^{
    666           1.1   elric 	    handle_write(c);
    667           1.1   elric 	    if ((c->flags & WAITING_WRITE) == 0) {
    668           1.1   elric 		dispatch_suspend(c->out);
    669           1.1   elric 	    }
    670           1.1   elric 	    maybe_close(c);
    671           1.1   elric 	});
    672       1.1.1.2  pettai 
    673           1.1   elric     dispatch_resume(c->in);
    674           1.1   elric #else
    675           1.1   elric     clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1));
    676           1.1   elric     clients[num_clients] = c;
    677           1.1   elric     num_clients++;
    678           1.1   elric #endif
    679           1.1   elric 
    680           1.1   elric     return c;
    681           1.1   elric }
    682           1.1   elric 
    683           1.1   elric static int
    684           1.1   elric maybe_close(struct client *c)
    685           1.1   elric {
    686           1.1   elric     if (c->calls != 0)
    687           1.1   elric 	return 0;
    688           1.1   elric     if (c->flags & (WAITING_READ|WAITING_WRITE))
    689           1.1   elric 	return 0;
    690           1.1   elric 
    691           1.1   elric #ifdef HAVE_GCD
    692           1.1   elric     dispatch_source_cancel(c->in);
    693           1.1   elric     if ((c->flags & WAITING_READ) == 0)
    694           1.1   elric 	dispatch_resume(c->in);
    695           1.1   elric     dispatch_release(c->in);
    696           1.1   elric 
    697           1.1   elric     dispatch_source_cancel(c->out);
    698           1.1   elric     if ((c->flags & WAITING_WRITE) == 0)
    699           1.1   elric 	dispatch_resume(c->out);
    700           1.1   elric     dispatch_release(c->out);
    701           1.1   elric #endif
    702           1.1   elric     close(c->fd); /* ref count fd close */
    703           1.1   elric     free(c);
    704           1.1   elric     return 1;
    705           1.1   elric }
    706           1.1   elric 
    707           1.1   elric 
    708           1.1   elric struct socket_call {
    709           1.1   elric     heim_idata in;
    710           1.1   elric     struct client *c;
    711           1.1   elric     heim_icred cred;
    712           1.1   elric };
    713           1.1   elric 
    714           1.1   elric static void
    715           1.1   elric output_data(struct client *c, const void *data, size_t len)
    716           1.1   elric {
    717           1.1   elric     if (c->olen + len < c->olen)
    718           1.1   elric 	abort();
    719           1.1   elric     c->outmsg = erealloc(c->outmsg, c->olen + len);
    720           1.1   elric     memcpy(&c->outmsg[c->olen], data, len);
    721           1.1   elric     c->olen += len;
    722           1.1   elric     c->flags |= WAITING_WRITE;
    723           1.1   elric }
    724           1.1   elric 
    725           1.1   elric static void
    726           1.1   elric socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
    727           1.1   elric {
    728           1.1   elric     struct socket_call *sc = (struct socket_call *)ctx;
    729           1.1   elric     struct client *c = sc->c;
    730           1.1   elric 
    731           1.1   elric     /* double complete ? */
    732           1.1   elric     if (c == NULL)
    733           1.1   elric 	abort();
    734           1.1   elric 
    735           1.1   elric     if ((c->flags & WAITING_CLOSE) == 0) {
    736           1.1   elric 	uint32_t u32;
    737           1.1   elric 
    738           1.1   elric 	/* length */
    739           1.1   elric 	u32 = htonl(reply->length);
    740           1.1   elric 	output_data(c, &u32, sizeof(u32));
    741           1.1   elric 
    742           1.1   elric 	/* return value */
    743           1.1   elric 	if (c->flags & INCLUDE_ERROR_CODE) {
    744           1.1   elric 	    u32 = htonl(returnvalue);
    745           1.1   elric 	    output_data(c, &u32, sizeof(u32));
    746           1.1   elric 	}
    747           1.1   elric 
    748           1.1   elric 	/* data */
    749           1.1   elric 	output_data(c, reply->data, reply->length);
    750           1.1   elric 
    751           1.1   elric 	/* if HTTP, close connection */
    752           1.1   elric 	if (c->flags & HTTP_REPLY) {
    753           1.1   elric 	    c->flags |= WAITING_CLOSE;
    754           1.1   elric 	    c->flags &= ~WAITING_READ;
    755           1.1   elric 	}
    756           1.1   elric     }
    757           1.1   elric 
    758           1.1   elric     c->calls--;
    759           1.1   elric     if (sc->cred)
    760           1.1   elric 	heim_ipc_free_cred(sc->cred);
    761           1.1   elric     free(sc->in.data);
    762           1.1   elric     sc->c = NULL; /* so we can catch double complete */
    763           1.1   elric     free(sc);
    764           1.1   elric 
    765           1.1   elric     maybe_close(c);
    766           1.1   elric }
    767           1.1   elric 
    768           1.1   elric /* remove HTTP %-quoting from buf */
    769           1.1   elric static int
    770           1.1   elric de_http(char *buf)
    771           1.1   elric {
    772           1.1   elric     unsigned char *p, *q;
    773           1.1   elric     for(p = q = (unsigned char *)buf; *p; p++, q++) {
    774           1.1   elric 	if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
    775           1.1   elric 	    unsigned int x;
    776           1.1   elric 	    if(sscanf((char *)p + 1, "%2x", &x) != 1)
    777           1.1   elric 		return -1;
    778           1.1   elric 	    *q = x;
    779           1.1   elric 	    p += 2;
    780           1.1   elric 	} else
    781           1.1   elric 	    *q = *p;
    782           1.1   elric     }
    783           1.1   elric     *q = '\0';
    784           1.1   elric     return 0;
    785           1.1   elric }
    786           1.1   elric 
    787           1.1   elric static struct socket_call *
    788           1.1   elric handle_http_tcp(struct client *c)
    789           1.1   elric {
    790           1.1   elric     struct socket_call *cs;
    791           1.1   elric     char *s, *p, *t;
    792           1.1   elric     void *data;
    793           1.1   elric     char *proto;
    794           1.1   elric     int len;
    795           1.1   elric 
    796           1.1   elric     s = (char *)c->inmsg;
    797           1.1   elric 
    798           1.1   elric     p = strstr(s, "\r\n");
    799           1.1   elric     if (p == NULL)
    800           1.1   elric 	return NULL;
    801           1.1   elric 
    802           1.1   elric     *p = 0;
    803           1.1   elric 
    804           1.1   elric     p = NULL;
    805           1.1   elric     t = strtok_r(s, " \t", &p);
    806           1.1   elric     if (t == NULL)
    807           1.1   elric 	return NULL;
    808           1.1   elric 
    809           1.1   elric     t = strtok_r(NULL, " \t", &p);
    810           1.1   elric     if (t == NULL)
    811           1.1   elric 	return NULL;
    812           1.1   elric 
    813           1.1   elric     data = malloc(strlen(t));
    814           1.1   elric     if (data == NULL)
    815           1.1   elric 	return NULL;
    816           1.1   elric 
    817           1.1   elric     if(*t == '/')
    818           1.1   elric 	t++;
    819           1.1   elric     if(de_http(t) != 0) {
    820           1.1   elric 	free(data);
    821           1.1   elric 	return NULL;
    822           1.1   elric     }
    823           1.1   elric     proto = strtok_r(NULL, " \t", &p);
    824           1.1   elric     if (proto == NULL) {
    825           1.1   elric 	free(data);
    826           1.1   elric 	return NULL;
    827           1.1   elric     }
    828  1.1.1.2.12.1     snj     len = rk_base64_decode(t, data);
    829           1.1   elric     if(len <= 0){
    830           1.1   elric 	const char *msg =
    831           1.1   elric 	    " 404 Not found\r\n"
    832           1.1   elric 	    "Server: Heimdal/" VERSION "\r\n"
    833           1.1   elric 	    "Cache-Control: no-cache\r\n"
    834           1.1   elric 	    "Pragma: no-cache\r\n"
    835           1.1   elric 	    "Content-type: text/html\r\n"
    836           1.1   elric 	    "Content-transfer-encoding: 8bit\r\n\r\n"
    837           1.1   elric 	    "<TITLE>404 Not found</TITLE>\r\n"
    838           1.1   elric 	    "<H1>404 Not found</H1>\r\n"
    839           1.1   elric 	    "That page doesn't exist, maybe you are looking for "
    840           1.1   elric 	    "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
    841           1.1   elric 	free(data);
    842           1.1   elric 	output_data(c, proto, strlen(proto));
    843           1.1   elric 	output_data(c, msg, strlen(msg));
    844           1.1   elric 	return NULL;
    845           1.1   elric     }
    846           1.1   elric 
    847           1.1   elric     cs = emalloc(sizeof(*cs));
    848           1.1   elric     cs->c = c;
    849           1.1   elric     cs->in.data = data;
    850           1.1   elric     cs->in.length = len;
    851           1.1   elric     c->ptr = 0;
    852           1.1   elric 
    853           1.1   elric     {
    854           1.1   elric 	const char *msg =
    855           1.1   elric 	    " 200 OK\r\n"
    856           1.1   elric 	    "Server: Heimdal/" VERSION "\r\n"
    857           1.1   elric 	    "Cache-Control: no-cache\r\n"
    858           1.1   elric 	    "Pragma: no-cache\r\n"
    859           1.1   elric 	    "Content-type: application/octet-stream\r\n"
    860           1.1   elric 	    "Content-transfer-encoding: binary\r\n\r\n";
    861           1.1   elric 	output_data(c, proto, strlen(proto));
    862           1.1   elric 	output_data(c, msg, strlen(msg));
    863           1.1   elric     }
    864           1.1   elric 
    865           1.1   elric     return cs;
    866           1.1   elric }
    867           1.1   elric 
    868           1.1   elric 
    869           1.1   elric static void
    870           1.1   elric handle_read(struct client *c)
    871           1.1   elric {
    872           1.1   elric     ssize_t len;
    873           1.1   elric     uint32_t dlen;
    874           1.1   elric 
    875           1.1   elric     if (c->flags & LISTEN_SOCKET) {
    876           1.1   elric 	add_new_socket(c->fd,
    877           1.1   elric 		       WAITING_READ | (c->flags & INHERIT_MASK),
    878           1.1   elric 		       c->callback,
    879           1.1   elric 		       c->userctx);
    880           1.1   elric 	return;
    881           1.1   elric     }
    882           1.1   elric 
    883           1.1   elric     if (c->ptr - c->len < 1024) {
    884           1.1   elric 	c->inmsg = erealloc(c->inmsg,
    885           1.1   elric 			    c->len + 1024);
    886           1.1   elric 	c->len += 1024;
    887           1.1   elric     }
    888       1.1.1.2  pettai 
    889           1.1   elric     len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr);
    890           1.1   elric     if (len <= 0) {
    891           1.1   elric 	c->flags |= WAITING_CLOSE;
    892           1.1   elric 	c->flags &= ~WAITING_READ;
    893           1.1   elric 	return;
    894           1.1   elric     }
    895           1.1   elric     c->ptr += len;
    896           1.1   elric     if (c->ptr > c->len)
    897           1.1   elric 	abort();
    898       1.1.1.2  pettai 
    899           1.1   elric     while (c->ptr >= sizeof(dlen)) {
    900           1.1   elric 	struct socket_call *cs;
    901       1.1.1.2  pettai 
    902           1.1   elric 	if((c->flags & ALLOW_HTTP) && c->ptr >= 4 &&
    903           1.1   elric 	   strncmp((char *)c->inmsg, "GET ", 4) == 0 &&
    904           1.1   elric 	   strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) {
    905           1.1   elric 
    906           1.1   elric 	    /* remove the trailing \r\n\r\n so the string is NUL terminated */
    907           1.1   elric 	    c->inmsg[c->ptr - 4] = '\0';
    908           1.1   elric 
    909           1.1   elric 	    c->flags |= HTTP_REPLY;
    910           1.1   elric 
    911           1.1   elric 	    cs = handle_http_tcp(c);
    912           1.1   elric 	    if (cs == NULL) {
    913           1.1   elric 		c->flags |= WAITING_CLOSE;
    914           1.1   elric 		c->flags &= ~WAITING_READ;
    915           1.1   elric 		break;
    916           1.1   elric 	    }
    917           1.1   elric 	} else {
    918           1.1   elric 	    memcpy(&dlen, c->inmsg, sizeof(dlen));
    919           1.1   elric 	    dlen = ntohl(dlen);
    920           1.1   elric 
    921           1.1   elric 	    if (dlen > MAX_PACKET_SIZE) {
    922           1.1   elric 		c->flags |= WAITING_CLOSE;
    923           1.1   elric 		c->flags &= ~WAITING_READ;
    924           1.1   elric 		return;
    925           1.1   elric 	    }
    926           1.1   elric 	    if (dlen > c->ptr - sizeof(dlen)) {
    927           1.1   elric 		break;
    928           1.1   elric 	    }
    929       1.1.1.2  pettai 
    930           1.1   elric 	    cs = emalloc(sizeof(*cs));
    931           1.1   elric 	    cs->c = c;
    932           1.1   elric 	    cs->in.data = emalloc(dlen);
    933           1.1   elric 	    memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
    934           1.1   elric 	    cs->in.length = dlen;
    935       1.1.1.2  pettai 
    936           1.1   elric 	    c->ptr -= sizeof(dlen) + dlen;
    937           1.1   elric 	    memmove(c->inmsg,
    938           1.1   elric 		    c->inmsg + sizeof(dlen) + dlen,
    939           1.1   elric 		    c->ptr);
    940           1.1   elric 	}
    941       1.1.1.2  pettai 
    942           1.1   elric 	c->calls++;
    943           1.1   elric 
    944           1.1   elric 	if ((c->flags & UNIX_SOCKET) != 0) {
    945           1.1   elric 	    if (update_client_creds(c))
    946       1.1.1.2  pettai 		_heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid,
    947           1.1   elric 				      c->unixrights.pid, -1, &cs->cred);
    948           1.1   elric 	}
    949           1.1   elric 
    950           1.1   elric 	c->callback(c->userctx, &cs->in,
    951           1.1   elric 		    cs->cred, socket_complete,
    952           1.1   elric 		    (heim_sipc_call)cs);
    953           1.1   elric     }
    954           1.1   elric }
    955           1.1   elric 
    956           1.1   elric static void
    957           1.1   elric handle_write(struct client *c)
    958           1.1   elric {
    959           1.1   elric     ssize_t len;
    960           1.1   elric 
    961           1.1   elric     len = write(c->fd, c->outmsg, c->olen);
    962           1.1   elric     if (len <= 0) {
    963           1.1   elric 	c->flags |= WAITING_CLOSE;
    964           1.1   elric 	c->flags &= ~(WAITING_WRITE);
    965       1.1.1.2  pettai     } else if (c->olen != (size_t)len) {
    966           1.1   elric 	memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len);
    967           1.1   elric 	c->olen -= len;
    968           1.1   elric     } else {
    969           1.1   elric 	c->olen = 0;
    970           1.1   elric 	free(c->outmsg);
    971           1.1   elric 	c->outmsg = NULL;
    972           1.1   elric 	c->flags &= ~(WAITING_WRITE);
    973           1.1   elric     }
    974           1.1   elric }
    975           1.1   elric 
    976           1.1   elric 
    977           1.1   elric #ifndef HAVE_GCD
    978           1.1   elric 
    979           1.1   elric static void
    980           1.1   elric process_loop(void)
    981           1.1   elric {
    982           1.1   elric     struct pollfd *fds;
    983           1.1   elric     unsigned n;
    984           1.1   elric     unsigned num_fds;
    985           1.1   elric 
    986  1.1.1.2.12.1     snj     while (num_clients > 0) {
    987           1.1   elric 
    988           1.1   elric 	fds = malloc(num_clients * sizeof(fds[0]));
    989           1.1   elric 	if(fds == NULL)
    990           1.1   elric 	    abort();
    991           1.1   elric 
    992           1.1   elric 	num_fds = num_clients;
    993           1.1   elric 
    994           1.1   elric 	for (n = 0 ; n < num_fds; n++) {
    995           1.1   elric 	    fds[n].fd = clients[n]->fd;
    996           1.1   elric 	    fds[n].events = 0;
    997           1.1   elric 	    if (clients[n]->flags & WAITING_READ)
    998           1.1   elric 		fds[n].events |= POLLIN;
    999           1.1   elric 	    if (clients[n]->flags & WAITING_WRITE)
   1000           1.1   elric 		fds[n].events |= POLLOUT;
   1001       1.1.1.2  pettai 
   1002           1.1   elric 	    fds[n].revents = 0;
   1003           1.1   elric 	}
   1004           1.1   elric 
   1005  1.1.1.2.12.1     snj 	while (poll(fds, num_fds, -1) == -1) {
   1006  1.1.1.2.12.1     snj             if (errno == EINTR || errno == EAGAIN)
   1007  1.1.1.2.12.1     snj                 continue;
   1008  1.1.1.2.12.1     snj             err(1, "poll(2) failed");
   1009  1.1.1.2.12.1     snj         }
   1010           1.1   elric 
   1011           1.1   elric 	for (n = 0 ; n < num_fds; n++) {
   1012           1.1   elric 	    if (clients[n] == NULL)
   1013           1.1   elric 		continue;
   1014           1.1   elric 	    if (fds[n].revents & POLLERR) {
   1015           1.1   elric 		clients[n]->flags |= WAITING_CLOSE;
   1016           1.1   elric 		continue;
   1017           1.1   elric 	    }
   1018           1.1   elric 
   1019           1.1   elric 	    if (fds[n].revents & POLLIN)
   1020           1.1   elric 		handle_read(clients[n]);
   1021           1.1   elric 	    if (fds[n].revents & POLLOUT)
   1022           1.1   elric 		handle_write(clients[n]);
   1023           1.1   elric 	}
   1024           1.1   elric 
   1025           1.1   elric 	n = 0;
   1026           1.1   elric 	while (n < num_clients) {
   1027           1.1   elric 	    struct client *c = clients[n];
   1028           1.1   elric 	    if (maybe_close(c)) {
   1029           1.1   elric 		if (n < num_clients - 1)
   1030           1.1   elric 		    clients[n] = clients[num_clients - 1];
   1031           1.1   elric 		num_clients--;
   1032           1.1   elric 	    } else
   1033           1.1   elric 		n++;
   1034           1.1   elric 	}
   1035           1.1   elric 
   1036           1.1   elric 	free(fds);
   1037           1.1   elric     }
   1038           1.1   elric }
   1039           1.1   elric 
   1040           1.1   elric #endif
   1041           1.1   elric 
   1042           1.1   elric static int
   1043           1.1   elric socket_release(heim_sipc ctx)
   1044           1.1   elric {
   1045           1.1   elric     struct client *c = ctx->mech;
   1046           1.1   elric     c->flags |= WAITING_CLOSE;
   1047           1.1   elric     return 0;
   1048           1.1   elric }
   1049           1.1   elric 
   1050           1.1   elric int
   1051           1.1   elric heim_sipc_stream_listener(int fd, int type,
   1052           1.1   elric 			  heim_ipc_callback callback,
   1053           1.1   elric 			  void *user, heim_sipc *ctx)
   1054           1.1   elric {
   1055           1.1   elric     heim_sipc ct = calloc(1, sizeof(*ct));
   1056           1.1   elric     struct client *c;
   1057           1.1   elric 
   1058           1.1   elric     if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP)))
   1059           1.1   elric 	return EINVAL;
   1060           1.1   elric 
   1061           1.1   elric     switch (type) {
   1062           1.1   elric     case HEIM_SIPC_TYPE_IPC:
   1063           1.1   elric 	c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user);
   1064           1.1   elric 	break;
   1065           1.1   elric     case HEIM_SIPC_TYPE_UINT32:
   1066           1.1   elric 	c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
   1067           1.1   elric 	break;
   1068           1.1   elric     case HEIM_SIPC_TYPE_HTTP:
   1069           1.1   elric     case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP:
   1070           1.1   elric 	c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user);
   1071           1.1   elric 	break;
   1072           1.1   elric     default:
   1073           1.1   elric 	free(ct);
   1074           1.1   elric 	return EINVAL;
   1075           1.1   elric     }
   1076           1.1   elric 
   1077           1.1   elric     ct->mech = c;
   1078           1.1   elric     ct->release = socket_release;
   1079           1.1   elric 
   1080           1.1   elric     c->unixrights.uid = (uid_t) -1;
   1081           1.1   elric     c->unixrights.gid = (gid_t) -1;
   1082           1.1   elric     c->unixrights.pid = (pid_t) 0;
   1083           1.1   elric 
   1084           1.1   elric     *ctx = ct;
   1085           1.1   elric     return 0;
   1086           1.1   elric }
   1087           1.1   elric 
   1088           1.1   elric int
   1089           1.1   elric heim_sipc_service_unix(const char *service,
   1090           1.1   elric 		       heim_ipc_callback callback,
   1091           1.1   elric 		       void *user, heim_sipc *ctx)
   1092           1.1   elric {
   1093           1.1   elric     struct sockaddr_un un;
   1094           1.1   elric     int fd, ret;
   1095           1.1   elric 
   1096           1.1   elric     un.sun_family = AF_UNIX;
   1097           1.1   elric 
   1098           1.1   elric     snprintf(un.sun_path, sizeof(un.sun_path),
   1099           1.1   elric 	     "/var/run/.heim_%s-socket", service);
   1100           1.1   elric     fd = socket(AF_UNIX, SOCK_STREAM, 0);
   1101           1.1   elric     if (fd < 0)
   1102           1.1   elric 	return errno;
   1103           1.1   elric 
   1104           1.1   elric     socket_set_reuseaddr(fd, 1);
   1105           1.1   elric #ifdef LOCAL_CREDS
   1106           1.1   elric     {
   1107           1.1   elric 	int one = 1;
   1108           1.1   elric 	setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
   1109           1.1   elric     }
   1110           1.1   elric #endif
   1111           1.1   elric 
   1112           1.1   elric     unlink(un.sun_path);
   1113           1.1   elric 
   1114           1.1   elric     if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
   1115           1.1   elric 	close(fd);
   1116           1.1   elric 	return errno;
   1117           1.1   elric     }
   1118           1.1   elric 
   1119           1.1   elric     if (listen(fd, SOMAXCONN) < 0) {
   1120           1.1   elric 	close(fd);
   1121           1.1   elric 	return errno;
   1122           1.1   elric     }
   1123           1.1   elric 
   1124           1.1   elric     chmod(un.sun_path, 0666);
   1125           1.1   elric 
   1126           1.1   elric     ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
   1127           1.1   elric 				    callback, user, ctx);
   1128           1.1   elric     if (ret == 0) {
   1129           1.1   elric 	struct client *c = (*ctx)->mech;
   1130           1.1   elric 	c->flags |= UNIX_SOCKET;
   1131           1.1   elric     }
   1132           1.1   elric 
   1133           1.1   elric     return ret;
   1134           1.1   elric }
   1135           1.1   elric 
   1136           1.1   elric /**
   1137           1.1   elric  * Set the idle timeout value
   1138           1.1   elric 
   1139           1.1   elric  * The timeout event handler is triggered recurrently every idle
   1140           1.1   elric  * period `t'. The default action is rather draconian and just calls
   1141           1.1   elric  * exit(0), so you might want to change this to something more
   1142           1.1   elric  * graceful using heim_sipc_set_timeout_handler().
   1143           1.1   elric  */
   1144           1.1   elric 
   1145           1.1   elric void
   1146           1.1   elric heim_sipc_timeout(time_t t)
   1147           1.1   elric {
   1148           1.1   elric #ifdef HAVE_GCD
   1149           1.1   elric     static dispatch_once_t timeoutonce;
   1150           1.1   elric     init_globals();
   1151           1.1   elric     dispatch_sync(timerq, ^{
   1152           1.1   elric 	    timeoutvalue = t;
   1153           1.1   elric 	    set_timer();
   1154           1.1   elric 	});
   1155           1.1   elric     dispatch_once(&timeoutonce, ^{  dispatch_resume(timer); });
   1156           1.1   elric #else
   1157           1.1   elric     abort();
   1158           1.1   elric #endif
   1159           1.1   elric }
   1160           1.1   elric 
   1161           1.1   elric /**
   1162           1.1   elric  * Set the timeout event handler
   1163           1.1   elric  *
   1164           1.1   elric  * Replaces the default idle timeout action.
   1165           1.1   elric  */
   1166           1.1   elric 
   1167           1.1   elric void
   1168           1.1   elric heim_sipc_set_timeout_handler(void (*func)(void))
   1169           1.1   elric {
   1170           1.1   elric #ifdef HAVE_GCD
   1171           1.1   elric     init_globals();
   1172           1.1   elric     dispatch_sync(timerq, ^{ timer_ev = func; });
   1173           1.1   elric #else
   1174           1.1   elric     abort();
   1175           1.1   elric #endif
   1176           1.1   elric }
   1177           1.1   elric 
   1178           1.1   elric 
   1179           1.1   elric void
   1180           1.1   elric heim_sipc_free_context(heim_sipc ctx)
   1181           1.1   elric {
   1182           1.1   elric     (ctx->release)(ctx);
   1183           1.1   elric }
   1184           1.1   elric 
   1185           1.1   elric void
   1186           1.1   elric heim_ipc_main(void)
   1187           1.1   elric {
   1188           1.1   elric #ifdef HAVE_GCD
   1189           1.1   elric     dispatch_main();
   1190           1.1   elric #else
   1191           1.1   elric     process_loop();
   1192           1.1   elric #endif
   1193           1.1   elric }
   1194           1.1   elric 
   1195