]> git.saurik.com Git - apple/launchd.git/blame - liblaunch/liblaunch.c
launchd-842.1.4.tar.gz
[apple/launchd.git] / liblaunch / liblaunch.c
CommitLineData
e91b9f68 1/*
95379394 2 * Copyright (c) 2005-2012 Apple Inc. All rights reserved.
e91b9f68 3 *
ed34e3c3 4 * @APPLE_APACHE_LICENSE_HEADER_START@
e91b9f68 5 *
ed34e3c3
A
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
e91b9f68 9 *
ed34e3c3
A
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
e91b9f68
A
16 * limitations under the License.
17 *
ed34e3c3 18 * @APPLE_APACHE_LICENSE_HEADER_END@
e91b9f68 19 */
5b0a4722
A
20
21#include "config.h"
ef398931
A
22#include "launch.h"
23#include "launch_priv.h"
24#include "launch_internal.h"
eabd1701 25#include "ktrace.h"
5b0a4722 26
ed34e3c3 27#include <mach/mach.h>
aa59983a 28#include <libkern/OSByteOrder.h>
e91b9f68
A
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/fcntl.h>
32#include <sys/un.h>
33#include <sys/uio.h>
ed34e3c3 34#include <sys/stat.h>
e91b9f68
A
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <pthread.h>
39#include <unistd.h>
40#include <errno.h>
ed34e3c3 41#include <pwd.h>
5b0a4722 42#include <assert.h>
ddbbfbc1
A
43#include <uuid/uuid.h>
44#include <sys/syscall.h>
dcace88f 45#include <dlfcn.h>
ddbbfbc1
A
46
47#ifdef __LP64__
48/* workaround: 5723161 */
49#ifndef __DARWIN_ALIGN32
50#define __DARWIN_ALIGN32(x) (((size_t)(x) + 3) & ~3)
51#endif
52#undef CMSG_DATA
53#define CMSG_DATA(cmsg) \
54 ((uint8_t *)(cmsg) + __DARWIN_ALIGN32(sizeof(struct cmsghdr)))
55#undef CMSG_SPACE
56#define CMSG_SPACE(l) \
57 (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + __DARWIN_ALIGN32(l))
58#undef CMSG_LEN
59#define CMSG_LEN(l) \
60 (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + (l))
61#endif
e91b9f68 62
eabd1701
A
63struct _launch_data {
64 uint64_t type;
65 union {
66 struct {
67 union {
68 launch_data_t *_array;
69 char *string;
70 void *opaque;
71 int64_t __junk;
72 };
73 union {
74 uint64_t _array_cnt;
75 uint64_t string_len;
76 uint64_t opaque_size;
77 };
78 };
79 int64_t fd;
80 uint64_t mp;
81 uint64_t err;
82 int64_t number;
83 uint64_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
84 double float_num;
85 };
86};
87
ef398931
A
88#include "bootstrap.h"
89#include "vproc.h"
90#include "vproc_priv.h"
91#include "vproc_internal.h"
e91b9f68 92
aa59983a
A
93/* __OSBogusByteSwap__() must not really exist in the symbol namespace
94 * in order for the following to generate an error at build time.
95 */
96extern void __OSBogusByteSwap__(void);
97
ddbbfbc1 98#define host2wire(x) \
aa59983a
A
99 ({ typeof (x) _X, _x = (x); \
100 switch (sizeof(_x)) { \
101 case 8: \
ddbbfbc1 102 _X = OSSwapHostToLittleInt64(_x); \
aa59983a
A
103 break; \
104 case 4: \
ddbbfbc1 105 _X = OSSwapHostToLittleInt32(_x); \
aa59983a
A
106 break; \
107 case 2: \
ddbbfbc1 108 _X = OSSwapHostToLittleInt16(_x); \
aa59983a
A
109 break; \
110 case 1: \
111 _X = _x; \
112 break; \
113 default: \
114 __OSBogusByteSwap__(); \
115 break; \
116 } \
117 _X; \
118 })
119
120
ddbbfbc1 121#define big2wire(x) \
aa59983a
A
122 ({ typeof (x) _X, _x = (x); \
123 switch (sizeof(_x)) { \
124 case 8: \
ddbbfbc1 125 _X = OSSwapLittleToHostInt64(_x); \
aa59983a
A
126 break; \
127 case 4: \
ddbbfbc1 128 _X = OSSwapLittleToHostInt32(_x); \
aa59983a
A
129 break; \
130 case 2: \
ddbbfbc1 131 _X = OSSwapLittleToHostInt16(_x); \
aa59983a
A
132 break; \
133 case 1: \
134 _X = _x; \
135 break; \
136 default: \
137 __OSBogusByteSwap__(); \
138 break; \
139 } \
140 _X; \
141 })
142
eabd1701
A
143union _launch_double_u {
144 uint64_t iv;
145 double dv;
146};
147
148#define host2wire_f(x) ({ \
149 typeof(x) _F, _f = (x); \
150 union _launch_double_u s; \
151 s.dv = _f; \
152 s.iv = host2wire(s.iv); \
153 _F = s.dv; \
154 _F; \
155})
156
157#define big2wire_f(x) ({ \
158 typeof(x) _F, _f = (x); \
159 union _launch_double_u s; \
160 s.dv = _f; \
161 s.iv = big2wire(s.iv); \
162 _F = s.dv; \
163 _F; \
164})
165
aa59983a
A
166
167struct launch_msg_header {
168 uint64_t magic;
169 uint64_t len;
170};
171
172#define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
173
ddbbfbc1
A
174enum {
175 LAUNCHD_USE_CHECKIN_FD,
176 LAUNCHD_USE_OTHER_FD,
177};
e91b9f68
A
178struct _launch {
179 void *sendbuf;
ed34e3c3 180 int *sendfds;
e91b9f68 181 void *recvbuf;
ed34e3c3
A
182 int *recvfds;
183 size_t sendlen;
184 size_t sendfdcnt;
185 size_t recvlen;
186 size_t recvfdcnt;
ddbbfbc1
A
187 int which;
188 int cifd;
ed34e3c3 189 int fd;
e91b9f68
A
190};
191
ed34e3c3 192static launch_data_t launch_data_array_pop_first(launch_data_t where);
e91b9f68 193static int _fd(int fd);
ed34e3c3
A
194static void launch_client_init(void);
195static void launch_msg_getmsgs(launch_data_t m, void *context);
196static launch_data_t launch_msg_internal(launch_data_t d);
197static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
e91b9f68 198
95379394
A
199void
200_launch_init_globals(launch_globals_t globals)
201{
202 pthread_once_t once = PTHREAD_ONCE_INIT;
203 globals->lc_once = once;
204 pthread_mutex_init(&globals->lc_mtx, NULL);
205}
e91b9f68 206
95379394
A
207#if !_LIBLAUNCH_HAS_ALLOC_ONCE
208launch_globals_t __launch_globals;
209
210void
211_launch_globals_init(void)
212{
213 __launch_globals = calloc(1, sizeof(struct launch_globals_s));
214 _launch_init_globals(__launch_globals);
215}
ddbbfbc1 216
95379394
A
217launch_globals_t
218_launch_globals_impl(void)
219{
220 static pthread_once_t once = PTHREAD_ONCE_INIT;
221 pthread_once(&once, &_launch_globals_init);
222 return __launch_globals;
223}
224#endif
e91b9f68 225
ed34e3c3
A
226void
227launch_client_init(void)
e91b9f68
A
228{
229 struct sockaddr_un sun;
230 char *where = getenv(LAUNCHD_SOCKET_ENV);
231 char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
ddbbfbc1 232 int dfd, lfd = -1, cifd = -1;
5b0a4722 233 name_t spath;
eabd1701 234
e91b9f68 235 if (_launchd_fd) {
ddbbfbc1
A
236 cifd = strtol(_launchd_fd, NULL, 10);
237 if ((dfd = dup(cifd)) >= 0) {
ed34e3c3 238 close(dfd);
ddbbfbc1 239 _fd(cifd);
e91b9f68 240 } else {
ddbbfbc1 241 cifd = -1;
e91b9f68
A
242 }
243 unsetenv(LAUNCHD_TRUSTED_FD_ENV);
244 }
eabd1701 245
ddbbfbc1
A
246 memset(&sun, 0, sizeof(sun));
247 sun.sun_family = AF_UNIX;
eabd1701 248
ddbbfbc1
A
249 /* The rules are as follows.
250 * - All users (including root) talk to their per-user launchd's by default.
251 * - If we have been invoked under sudo, talk to the system launchd.
252 * - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then
253 * talk to the system launchd.
254 */
255 if (where && where[0] != '\0') {
256 strncpy(sun.sun_path, where, sizeof(sun.sun_path));
257 } else {
dcace88f
A
258 if (_vprocmgr_getsocket(spath) == 0) {
259 if ((getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0) {
ddbbfbc1
A
260 /* Talk to the system launchd. */
261 strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
262 } else {
263 /* Talk to our per-user launchd. */
264 size_t min_len;
eabd1701 265
ddbbfbc1 266 min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath);
eabd1701 267
ddbbfbc1
A
268 strncpy(sun.sun_path, spath, min_len);
269 }
270 }
271 }
eabd1701 272
95379394 273 launch_globals_t globals = _launch_globals();
ddbbfbc1
A
274 if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) {
275 goto out_bad;
276 }
eabd1701 277
ddbbfbc1 278#if TARGET_OS_EMBEDDED
95379394 279 (void)vproc_swap_integer(NULL, VPROC_GSK_EMBEDDEDROOTEQUIVALENT, NULL, &globals->s_am_embedded_god);
ddbbfbc1
A
280#endif
281 if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) {
95379394 282 if (cifd != -1 || globals->s_am_embedded_god) {
ddbbfbc1
A
283 /* There is NO security enforced by this check. This is just a hint to our
284 * library that we shouldn't error out due to failing to open this socket. If
285 * we inherited a trusted file descriptor, we shouldn't fail. This should be
286 * adequate for clients' expectations.
287 */
288 close(lfd);
289 lfd = -1;
ed34e3c3 290 } else {
e91b9f68 291 goto out_bad;
ddbbfbc1 292 }
e91b9f68 293 }
95379394
A
294
295 if (!(globals->l = launchd_fdopen(lfd, cifd))) {
e91b9f68 296 goto out_bad;
ddbbfbc1 297 }
eabd1701 298
95379394 299 if (!(globals->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
e91b9f68 300 goto out_bad;
ddbbfbc1 301 }
eabd1701 302
e91b9f68
A
303 return;
304out_bad:
95379394
A
305 if (globals->l) {
306 launchd_close(globals->l, close);
307 globals->l = NULL;
308 } else if (lfd != -1) {
ed34e3c3 309 close(lfd);
95379394 310 }
dcace88f 311 if (cifd != -1) {
ddbbfbc1
A
312 close(cifd);
313 }
e91b9f68
A
314}
315
ed34e3c3
A
316launch_data_t
317launch_data_alloc(launch_data_type_t t)
e91b9f68 318{
dcace88f 319 launch_data_t d = calloc(1, sizeof(struct _launch_data));
e91b9f68
A
320
321 if (d) {
322 d->type = t;
323 switch (t) {
324 case LAUNCH_DATA_DICTIONARY:
325 case LAUNCH_DATA_ARRAY:
326 d->_array = malloc(0);
327 break;
dcace88f
A
328 case LAUNCH_DATA_OPAQUE:
329 d->opaque = malloc(0);
e91b9f68
A
330 default:
331 break;
332 }
333 }
334
335 return d;
336}
337
ed34e3c3
A
338launch_data_type_t
339launch_data_get_type(launch_data_t d)
e91b9f68
A
340{
341 return d->type;
342}
343
ed34e3c3
A
344void
345launch_data_free(launch_data_t d)
e91b9f68
A
346{
347 size_t i;
348
349 switch (d->type) {
350 case LAUNCH_DATA_DICTIONARY:
351 case LAUNCH_DATA_ARRAY:
dcace88f
A
352 for (i = 0; i < d->_array_cnt; i++) {
353 if (d->_array[i]) {
354 launch_data_free(d->_array[i]);
355 }
356 }
e91b9f68
A
357 free(d->_array);
358 break;
359 case LAUNCH_DATA_STRING:
360 if (d->string)
361 free(d->string);
362 break;
363 case LAUNCH_DATA_OPAQUE:
364 if (d->opaque)
365 free(d->opaque);
366 break;
367 default:
368 break;
369 }
370 free(d);
371}
372
ed34e3c3
A
373size_t
374launch_data_dict_get_count(launch_data_t dict)
e91b9f68
A
375{
376 return dict->_array_cnt / 2;
377}
378
ed34e3c3
A
379bool
380launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
e91b9f68
A
381{
382 size_t i;
ed34e3c3 383 launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING);
e91b9f68 384
ed34e3c3 385 launch_data_set_string(thekey, key);
e91b9f68
A
386
387 for (i = 0; i < dict->_array_cnt; i += 2) {
388 if (!strcasecmp(key, dict->_array[i]->string)) {
389 launch_data_array_set_index(dict, thekey, i);
390 launch_data_array_set_index(dict, what, i + 1);
391 return true;
392 }
393 }
394 launch_data_array_set_index(dict, thekey, i);
395 launch_data_array_set_index(dict, what, i + 1);
396 return true;
397}
398
ed34e3c3
A
399launch_data_t
400launch_data_dict_lookup(launch_data_t dict, const char *key)
e91b9f68
A
401{
402 size_t i;
403
ed34e3c3 404 if (LAUNCH_DATA_DICTIONARY != dict->type)
e91b9f68
A
405 return NULL;
406
407 for (i = 0; i < dict->_array_cnt; i += 2) {
408 if (!strcasecmp(key, dict->_array[i]->string))
409 return dict->_array[i + 1];
410 }
411
412 return NULL;
413}
414
ed34e3c3
A
415bool
416launch_data_dict_remove(launch_data_t dict, const char *key)
e91b9f68
A
417{
418 size_t i;
419
420 for (i = 0; i < dict->_array_cnt; i += 2) {
421 if (!strcasecmp(key, dict->_array[i]->string))
422 break;
423 }
424 if (i == dict->_array_cnt)
425 return false;
426 launch_data_free(dict->_array[i]);
427 launch_data_free(dict->_array[i + 1]);
428 memmove(dict->_array + i, dict->_array + i + 2, (dict->_array_cnt - (i + 2)) * sizeof(launch_data_t));
429 dict->_array_cnt -= 2;
430 return true;
431}
432
ed34e3c3
A
433void
434launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
e91b9f68
A
435{
436 size_t i;
437
ddbbfbc1 438 if (LAUNCH_DATA_DICTIONARY != dict->type) {
e91b9f68 439 return;
ddbbfbc1 440 }
e91b9f68 441
ddbbfbc1 442 for (i = 0; i < dict->_array_cnt; i += 2) {
e91b9f68 443 cb(dict->_array[i + 1], dict->_array[i]->string, context);
ddbbfbc1 444 }
e91b9f68
A
445}
446
ed34e3c3
A
447bool
448launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
e91b9f68
A
449{
450 if ((ind + 1) >= where->_array_cnt) {
5b0a4722 451 where->_array = reallocf(where->_array, (ind + 1) * sizeof(launch_data_t));
e91b9f68
A
452 memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t));
453 where->_array_cnt = ind + 1;
454 }
455
ddbbfbc1 456 if (where->_array[ind]) {
e91b9f68 457 launch_data_free(where->_array[ind]);
ddbbfbc1
A
458 }
459
e91b9f68
A
460 where->_array[ind] = what;
461 return true;
462}
463
ed34e3c3
A
464launch_data_t
465launch_data_array_get_index(launch_data_t where, size_t ind)
e91b9f68 466{
ddbbfbc1 467 if (LAUNCH_DATA_ARRAY != where->type || ind >= where->_array_cnt) {
e91b9f68 468 return NULL;
ddbbfbc1 469 } else {
e91b9f68 470 return where->_array[ind];
ddbbfbc1 471 }
e91b9f68
A
472}
473
ed34e3c3
A
474launch_data_t
475launch_data_array_pop_first(launch_data_t where)
e91b9f68
A
476{
477 launch_data_t r = NULL;
5b0a4722 478
e91b9f68
A
479 if (where->_array_cnt > 0) {
480 r = where->_array[0];
481 memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t));
482 where->_array_cnt--;
483 }
484 return r;
485}
486
ed34e3c3
A
487size_t
488launch_data_array_get_count(launch_data_t where)
e91b9f68 489{
ed34e3c3 490 if (LAUNCH_DATA_ARRAY != where->type)
e91b9f68
A
491 return 0;
492 return where->_array_cnt;
493}
494
ed34e3c3
A
495bool
496launch_data_set_errno(launch_data_t d, int e)
e91b9f68
A
497{
498 d->err = e;
499 return true;
500}
501
ed34e3c3
A
502bool
503launch_data_set_fd(launch_data_t d, int fd)
e91b9f68
A
504{
505 d->fd = fd;
506 return true;
507}
508
ed34e3c3
A
509bool
510launch_data_set_machport(launch_data_t d, mach_port_t p)
511{
512 d->mp = p;
513 return true;
514}
515
516bool
517launch_data_set_integer(launch_data_t d, long long n)
e91b9f68
A
518{
519 d->number = n;
520 return true;
521}
522
ed34e3c3
A
523bool
524launch_data_set_bool(launch_data_t d, bool b)
e91b9f68
A
525{
526 d->boolean = b;
527 return true;
528}
529
ed34e3c3
A
530bool
531launch_data_set_real(launch_data_t d, double n)
e91b9f68
A
532{
533 d->float_num = n;
534 return true;
535}
536
ed34e3c3
A
537bool
538launch_data_set_string(launch_data_t d, const char *s)
e91b9f68
A
539{
540 if (d->string)
541 free(d->string);
542 d->string = strdup(s);
543 if (d->string) {
544 d->string_len = strlen(d->string);
545 return true;
546 }
547 return false;
548}
549
ed34e3c3
A
550bool
551launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
e91b9f68
A
552{
553 d->opaque_size = os;
554 if (d->opaque)
555 free(d->opaque);
556 d->opaque = malloc(os);
557 if (d->opaque) {
558 memcpy(d->opaque, o, os);
559 return true;
560 }
561 return false;
562}
563
ed34e3c3
A
564int
565launch_data_get_errno(launch_data_t d)
e91b9f68
A
566{
567 return d->err;
568}
569
ed34e3c3
A
570int
571launch_data_get_fd(launch_data_t d)
e91b9f68
A
572{
573 return d->fd;
574}
575
ed34e3c3
A
576mach_port_t
577launch_data_get_machport(launch_data_t d)
578{
579 return d->mp;
580}
581
582long long
583launch_data_get_integer(launch_data_t d)
e91b9f68
A
584{
585 return d->number;
586}
587
ed34e3c3
A
588bool
589launch_data_get_bool(launch_data_t d)
e91b9f68
A
590{
591 return d->boolean;
592}
593
ed34e3c3
A
594double
595launch_data_get_real(launch_data_t d)
e91b9f68
A
596{
597 return d->float_num;
598}
599
ed34e3c3
A
600const char *
601launch_data_get_string(launch_data_t d)
e91b9f68 602{
ed34e3c3 603 if (LAUNCH_DATA_STRING != d->type)
e91b9f68
A
604 return NULL;
605 return d->string;
606}
607
ed34e3c3
A
608void *
609launch_data_get_opaque(launch_data_t d)
e91b9f68 610{
ed34e3c3 611 if (LAUNCH_DATA_OPAQUE != d->type)
e91b9f68
A
612 return NULL;
613 return d->opaque;
614}
615
ed34e3c3
A
616size_t
617launch_data_get_opaque_size(launch_data_t d)
e91b9f68
A
618{
619 return d->opaque_size;
620}
621
ed34e3c3
A
622int
623launchd_getfd(launch_t l)
e91b9f68 624{
eabd1701 625 return (l->which == LAUNCHD_USE_CHECKIN_FD) ? l->cifd : l->fd;
e91b9f68
A
626}
627
ed34e3c3 628launch_t
ddbbfbc1 629launchd_fdopen(int fd, int cifd)
e91b9f68 630{
5b0a4722 631 launch_t c;
e91b9f68 632
5b0a4722 633 c = calloc(1, sizeof(struct _launch));
e91b9f68
A
634 if (!c)
635 return NULL;
636
5b0a4722 637 c->fd = fd;
ddbbfbc1
A
638 c->cifd = cifd;
639
dcace88f 640 if (c->fd == -1 || (c->fd != -1 && c->cifd != -1)) {
ddbbfbc1 641 c->which = LAUNCHD_USE_CHECKIN_FD;
dcace88f 642 } else if (c->cifd == -1) {
ddbbfbc1
A
643 c->which = LAUNCHD_USE_OTHER_FD;
644 }
e91b9f68 645
ed34e3c3 646 fcntl(fd, F_SETFL, O_NONBLOCK);
ddbbfbc1 647 fcntl(cifd, F_SETFL, O_NONBLOCK);
e91b9f68 648
5b0a4722 649 if ((c->sendbuf = malloc(0)) == NULL)
e91b9f68 650 goto out_bad;
5b0a4722 651 if ((c->sendfds = malloc(0)) == NULL)
e91b9f68 652 goto out_bad;
5b0a4722 653 if ((c->recvbuf = malloc(0)) == NULL)
e91b9f68 654 goto out_bad;
5b0a4722 655 if ((c->recvfds = malloc(0)) == NULL)
e91b9f68
A
656 goto out_bad;
657
658 return c;
659
660out_bad:
661 if (c->sendbuf)
662 free(c->sendbuf);
663 if (c->sendfds)
664 free(c->sendfds);
665 if (c->recvbuf)
666 free(c->recvbuf);
667 if (c->recvfds)
668 free(c->recvfds);
669 free(c);
670 return NULL;
671}
672
ed34e3c3 673void
5b0a4722 674launchd_close(launch_t lh, typeof(close) closefunc)
e91b9f68 675{
95379394
A
676 launch_globals_t globals = _launch_globals();
677
678 if (globals->in_flight_msg_recv_client == lh) {
679 globals->in_flight_msg_recv_client = NULL;
f36da725
A
680 }
681
e91b9f68
A
682 if (lh->sendbuf)
683 free(lh->sendbuf);
684 if (lh->sendfds)
685 free(lh->sendfds);
686 if (lh->recvbuf)
687 free(lh->recvbuf);
688 if (lh->recvfds)
689 free(lh->recvfds);
5b0a4722 690 closefunc(lh->fd);
ddbbfbc1 691 closefunc(lh->cifd);
e91b9f68
A
692 free(lh);
693}
694
5b0a4722
A
695#define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
696
697size_t
698launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fd_cnt)
e91b9f68 699{
5b0a4722 700 launch_data_t o_in_w = where;
ddbbfbc1 701 size_t i, rsz, node_data_len = sizeof(struct _launch_data);
e91b9f68 702
ddbbfbc1 703 if (node_data_len > len) {
5b0a4722
A
704 return 0;
705 }
aa59983a 706
ddbbfbc1 707 where += node_data_len;
e91b9f68 708
ddbbfbc1 709 o_in_w->type = host2wire(d->type);
aa59983a 710
ddbbfbc1 711 size_t pad_len = 0;
e91b9f68 712 switch (d->type) {
aa59983a 713 case LAUNCH_DATA_INTEGER:
ddbbfbc1 714 o_in_w->number = host2wire(d->number);
aa59983a
A
715 break;
716 case LAUNCH_DATA_REAL:
eabd1701 717 o_in_w->float_num = host2wire_f(d->float_num);
aa59983a
A
718 break;
719 case LAUNCH_DATA_BOOL:
ddbbfbc1 720 o_in_w->boolean = host2wire(d->boolean);
aa59983a
A
721 break;
722 case LAUNCH_DATA_ERRNO:
ddbbfbc1 723 o_in_w->err = host2wire(d->err);
aa59983a 724 break;
e91b9f68 725 case LAUNCH_DATA_FD:
ddbbfbc1 726 o_in_w->fd = host2wire(d->fd);
5b0a4722
A
727 if (fd_where && d->fd != -1) {
728 fd_where[*fd_cnt] = d->fd;
729 (*fd_cnt)++;
e91b9f68
A
730 }
731 break;
732 case LAUNCH_DATA_STRING:
ddbbfbc1
A
733 o_in_w->string_len = host2wire(d->string_len);
734 node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1);
eabd1701 735
ddbbfbc1 736 if (node_data_len > len) {
5b0a4722
A
737 return 0;
738 }
ddbbfbc1 739 memcpy(where, d->string, d->string_len + 1);
eabd1701 740
ddbbfbc1
A
741 /* Zero padded data. */
742 pad_len = ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1) - (d->string_len + 1);
743 bzero(where + d->string_len + 1, pad_len);
eabd1701 744
e91b9f68
A
745 break;
746 case LAUNCH_DATA_OPAQUE:
ddbbfbc1
A
747 o_in_w->opaque_size = host2wire(d->opaque_size);
748 node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size);
749 if (node_data_len > len) {
5b0a4722
A
750 return 0;
751 }
752 memcpy(where, d->opaque, d->opaque_size);
eabd1701 753
ddbbfbc1
A
754 /* Zero padded data. */
755 pad_len = ROUND_TO_64BIT_WORD_SIZE(d->opaque_size) - d->opaque_size;
756 bzero(where + d->opaque_size, pad_len);
eabd1701 757
e91b9f68
A
758 break;
759 case LAUNCH_DATA_DICTIONARY:
760 case LAUNCH_DATA_ARRAY:
ddbbfbc1
A
761 o_in_w->_array_cnt = host2wire(d->_array_cnt);
762 node_data_len += d->_array_cnt * sizeof(uint64_t);
763 if (node_data_len > len) {
5b0a4722
A
764 return 0;
765 }
e91b9f68 766
5b0a4722
A
767 where += d->_array_cnt * sizeof(uint64_t);
768
769 for (i = 0; i < d->_array_cnt; i++) {
ddbbfbc1 770 rsz = launch_data_pack(d->_array[i], where, len - node_data_len, fd_where, fd_cnt);
5b0a4722
A
771 if (rsz == 0) {
772 return 0;
773 }
774 where += rsz;
ddbbfbc1 775 node_data_len += rsz;
5b0a4722 776 }
e91b9f68
A
777 break;
778 default:
779 break;
780 }
5b0a4722 781
ddbbfbc1 782 return node_data_len;
e91b9f68
A
783}
784
5b0a4722
A
785launch_data_t
786launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset)
e91b9f68 787{
5b0a4722 788 launch_data_t r = data + *data_offset;
aa59983a 789 size_t i, tmpcnt;
e91b9f68 790
5b0a4722 791 if ((data_size - *data_offset) < sizeof(struct _launch_data))
e91b9f68
A
792 return NULL;
793 *data_offset += sizeof(struct _launch_data);
794
ddbbfbc1 795 switch (big2wire(r->type)) {
e91b9f68
A
796 case LAUNCH_DATA_DICTIONARY:
797 case LAUNCH_DATA_ARRAY:
ddbbfbc1 798 tmpcnt = big2wire(r->_array_cnt);
5b0a4722 799 if ((data_size - *data_offset) < (tmpcnt * sizeof(uint64_t))) {
e91b9f68
A
800 errno = EAGAIN;
801 return NULL;
802 }
5b0a4722
A
803 r->_array = data + *data_offset;
804 *data_offset += tmpcnt * sizeof(uint64_t);
aa59983a 805 for (i = 0; i < tmpcnt; i++) {
5b0a4722 806 r->_array[i] = launch_data_unpack(data, data_size, fds, fd_cnt, data_offset, fdoffset);
e91b9f68
A
807 if (r->_array[i] == NULL)
808 return NULL;
809 }
aa59983a 810 r->_array_cnt = tmpcnt;
e91b9f68
A
811 break;
812 case LAUNCH_DATA_STRING:
ddbbfbc1 813 tmpcnt = big2wire(r->string_len);
5b0a4722 814 if ((data_size - *data_offset) < (tmpcnt + 1)) {
e91b9f68
A
815 errno = EAGAIN;
816 return NULL;
817 }
5b0a4722 818 r->string = data + *data_offset;
aa59983a 819 r->string_len = tmpcnt;
5b0a4722 820 *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt + 1);
e91b9f68
A
821 break;
822 case LAUNCH_DATA_OPAQUE:
ddbbfbc1 823 tmpcnt = big2wire(r->opaque_size);
5b0a4722 824 if ((data_size - *data_offset) < tmpcnt) {
e91b9f68
A
825 errno = EAGAIN;
826 return NULL;
827 }
5b0a4722 828 r->opaque = data + *data_offset;
aa59983a 829 r->opaque_size = tmpcnt;
5b0a4722 830 *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt);
e91b9f68
A
831 break;
832 case LAUNCH_DATA_FD:
5b0a4722
A
833 if (r->fd != -1 && fd_cnt > *fdoffset) {
834 r->fd = _fd(fds[*fdoffset]);
e91b9f68
A
835 *fdoffset += 1;
836 }
837 break;
838 case LAUNCH_DATA_INTEGER:
ddbbfbc1 839 r->number = big2wire(r->number);
aa59983a 840 break;
e91b9f68 841 case LAUNCH_DATA_REAL:
eabd1701 842 r->float_num = big2wire_f(r->float_num);
aa59983a 843 break;
e91b9f68 844 case LAUNCH_DATA_BOOL:
ddbbfbc1 845 r->boolean = big2wire(r->boolean);
aa59983a 846 break;
e91b9f68 847 case LAUNCH_DATA_ERRNO:
ddbbfbc1 848 r->err = big2wire(r->err);
ed34e3c3 849 case LAUNCH_DATA_MACHPORT:
e91b9f68
A
850 break;
851 default:
852 errno = EINVAL;
853 return NULL;
854 break;
855 }
856
ddbbfbc1 857 r->type = big2wire(r->type);
aa59983a 858
e91b9f68
A
859 return r;
860}
861
ddbbfbc1
A
862int
863launchd_msg_send(launch_t lh, launch_data_t d)
e91b9f68 864{
aa59983a 865 struct launch_msg_header lmh;
e91b9f68
A
866 struct cmsghdr *cm = NULL;
867 struct msghdr mh;
aa59983a 868 struct iovec iov[2];
e91b9f68 869 size_t sentctrllen = 0;
aa59983a 870 int r;
e91b9f68 871
ddbbfbc1 872 int fd2use = launchd_getfd(lh);
dcace88f 873 if (fd2use == -1) {
ddbbfbc1
A
874 errno = EPERM;
875 return -1;
876 }
877
e91b9f68
A
878 memset(&mh, 0, sizeof(mh));
879
5b0a4722
A
880 /* confirm that the next hack works */
881 assert((d && lh->sendlen == 0) || (!d && lh->sendlen));
882
aa59983a 883 if (d) {
5b0a4722
A
884 size_t fd_slots_used = 0;
885 size_t good_enough_size = 10 * 1024 * 1024;
886 uint64_t msglen;
887
888 /* hack, see the above assert to verify "correctness" */
889 free(lh->sendbuf);
890 lh->sendbuf = malloc(good_enough_size);
dcace88f
A
891 if (!lh->sendbuf) {
892 errno = ENOMEM;
893 return -1;
894 }
895
5b0a4722
A
896 free(lh->sendfds);
897 lh->sendfds = malloc(4 * 1024);
dcace88f
A
898 if (!lh->sendfds) {
899 free(lh->sendbuf);
900 lh->sendbuf = NULL;
901 errno = ENOMEM;
902 return -1;
903 }
5b0a4722
A
904
905 lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used);
906
907 if (lh->sendlen == 0) {
908 errno = ENOMEM;
909 return -1;
910 }
e91b9f68 911
5b0a4722 912 lh->sendfdcnt = fd_slots_used;
e91b9f68 913
ddbbfbc1
A
914 msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2wire() macro work right */
915 lmh.len = host2wire(msglen);
916 lmh.magic = host2wire(LAUNCH_MSG_HEADER_MAGIC);
aa59983a
A
917
918 iov[0].iov_base = &lmh;
919 iov[0].iov_len = sizeof(lmh);
920 mh.msg_iov = iov;
5b0a4722 921 mh.msg_iovlen = 2;
aa59983a
A
922 } else {
923 mh.msg_iov = iov + 1;
5b0a4722 924 mh.msg_iovlen = 1;
aa59983a
A
925 }
926
927 iov[1].iov_base = lh->sendbuf;
928 iov[1].iov_len = lh->sendlen;
929
930
e91b9f68
A
931 if (lh->sendfdcnt > 0) {
932 sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int));
933 cm = alloca(mh.msg_controllen);
934 mh.msg_control = cm;
935
936 memset(cm, 0, mh.msg_controllen);
937
938 cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int));
939 cm->cmsg_level = SOL_SOCKET;
940 cm->cmsg_type = SCM_RIGHTS;
941
942 memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int));
943 }
944
ddbbfbc1 945 if ((r = sendmsg(fd2use, &mh, 0)) == -1) {
e91b9f68
A
946 return -1;
947 } else if (r == 0) {
948 errno = ECONNRESET;
949 return -1;
950 } else if (sentctrllen != mh.msg_controllen) {
951 errno = ECONNRESET;
952 return -1;
953 }
954
aa59983a
A
955 if (d) {
956 r -= sizeof(struct launch_msg_header);
957 }
958
e91b9f68
A
959 lh->sendlen -= r;
960 if (lh->sendlen > 0) {
961 memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen);
962 } else {
963 free(lh->sendbuf);
964 lh->sendbuf = malloc(0);
965 }
966
967 lh->sendfdcnt = 0;
968 free(lh->sendfds);
969 lh->sendfds = malloc(0);
970
971 if (lh->sendlen > 0) {
972 errno = EAGAIN;
973 return -1;
974 }
975
976 return 0;
977}
978
ed34e3c3
A
979int
980launch_get_fd(void)
e91b9f68 981{
95379394
A
982 launch_globals_t globals = _launch_globals();
983 pthread_once(&globals->lc_once, launch_client_init);
e91b9f68 984
95379394 985 if (!globals->l) {
e91b9f68
A
986 errno = ENOTCONN;
987 return -1;
988 }
989
95379394 990 return globals->l->fd;
e91b9f68
A
991}
992
ed34e3c3
A
993void
994launch_msg_getmsgs(launch_data_t m, void *context)
e91b9f68
A
995{
996 launch_data_t async_resp, *sync_resp = context;
eabd1701 997
95379394
A
998 launch_globals_t globals = _launch_globals();
999
e91b9f68 1000 if ((LAUNCH_DATA_DICTIONARY == launch_data_get_type(m)) && (async_resp = launch_data_dict_lookup(m, LAUNCHD_ASYNC_MSG_KEY))) {
95379394 1001 launch_data_array_set_index(globals->async_resp, launch_data_copy(async_resp), launch_data_array_get_count(globals->async_resp));
e91b9f68
A
1002 } else {
1003 *sync_resp = launch_data_copy(m);
1004 }
1005}
1006
ed34e3c3
A
1007void
1008launch_mach_checkin_service(launch_data_t obj, const char *key, void *context __attribute__((unused)))
1009{
1010 kern_return_t result;
1011 mach_port_t p;
1012 name_t srvnm;
1013
1014 strlcpy(srvnm, key, sizeof(srvnm));
1015
1016 result = bootstrap_check_in(bootstrap_port, srvnm, &p);
1017
1018 if (result == BOOTSTRAP_SUCCESS)
1019 launch_data_set_machport(obj, p);
1020}
1021
1022launch_data_t
1023launch_msg(launch_data_t d)
1024{
1025 launch_data_t mps, r = launch_msg_internal(d);
1026
1027 if (launch_data_get_type(d) == LAUNCH_DATA_STRING) {
1028 if (strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) != 0)
1029 return r;
1030 if (r == NULL)
1031 return r;
1032 if (launch_data_get_type(r) != LAUNCH_DATA_DICTIONARY)
1033 return r;
1034 mps = launch_data_dict_lookup(r, LAUNCH_JOBKEY_MACHSERVICES);
1035 if (mps == NULL)
1036 return r;
1037 launch_data_dict_iterate(mps, launch_mach_checkin_service, NULL);
1038 }
1039
1040 return r;
1041}
1042
ddbbfbc1
A
1043extern kern_return_t vproc_mig_set_security_session(mach_port_t, uuid_t, mach_port_t);
1044
1045static inline bool
1046uuid_data_is_null(launch_data_t d)
1047{
1048 bool result = false;
dcace88f 1049 if (launch_data_get_type(d) == LAUNCH_DATA_OPAQUE && launch_data_get_opaque_size(d) == sizeof(uuid_t)) {
ddbbfbc1
A
1050 uuid_t existing_uuid;
1051 memcpy(existing_uuid, launch_data_get_opaque(d), sizeof(uuid_t));
eabd1701 1052
ddbbfbc1
A
1053 /* A NULL UUID tells us to keep the session inherited from the parent. */
1054 result = (bool)uuid_is_null(existing_uuid);
1055 }
eabd1701 1056
ddbbfbc1
A
1057 return result;
1058}
1059
ed34e3c3
A
1060launch_data_t
1061launch_msg_internal(launch_data_t d)
e91b9f68
A
1062{
1063 launch_data_t resp = NULL;
1064
5b0a4722
A
1065 if (d && (launch_data_get_type(d) == LAUNCH_DATA_STRING)
1066 && (strcmp(launch_data_get_string(d), LAUNCH_KEY_GETJOBS) == 0)
1067 && vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) {
1068 return resp;
1069 }
1070
95379394
A
1071 launch_globals_t globals = _launch_globals();
1072 pthread_once(&globals->lc_once, launch_client_init);
1073 if (!globals->l) {
e91b9f68
A
1074 errno = ENOTCONN;
1075 return NULL;
1076 }
1077
ddbbfbc1 1078 int fd2use = -1;
95379394
A
1079 if ((launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0) || globals->s_am_embedded_god) {
1080 globals->l->which = LAUNCHD_USE_CHECKIN_FD;
ddbbfbc1 1081 } else {
95379394 1082 globals->l->which = LAUNCHD_USE_OTHER_FD;
ddbbfbc1 1083 }
eabd1701 1084
95379394 1085 fd2use = launchd_getfd(globals->l);
eabd1701 1086
dcace88f 1087 if (fd2use == -1) {
ddbbfbc1
A
1088 errno = EPERM;
1089 return NULL;
1090 }
eabd1701 1091
ddbbfbc1
A
1092#if !TARGET_OS_EMBEDDED
1093 uuid_t uuid;
1094 launch_data_t uuid_d = NULL;
1095 size_t jobs_that_need_sessions = 0;
dcace88f 1096 if (d && launch_data_get_type(d) == LAUNCH_DATA_DICTIONARY) {
ddbbfbc1
A
1097 launch_data_t v = launch_data_dict_lookup(d, LAUNCH_KEY_SUBMITJOB);
1098
dcace88f 1099 if (v && launch_data_get_type(v) == LAUNCH_DATA_ARRAY) {
ddbbfbc1
A
1100 size_t cnt = launch_data_array_get_count(v);
1101 size_t i = 0;
1102
1103 uuid_generate(uuid);
dcace88f 1104 for (i = 0; i < cnt; i++) {
ddbbfbc1 1105 launch_data_t ji = launch_data_array_get_index(v, i);
dcace88f 1106 if (launch_data_get_type(ji) == LAUNCH_DATA_DICTIONARY) {
ddbbfbc1 1107 launch_data_t existing_v = launch_data_dict_lookup(ji, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
dcace88f 1108 if (!existing_v) {
ddbbfbc1
A
1109 /* I really wish these were reference-counted. Sigh... */
1110 uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
1111 launch_data_dict_insert(ji, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
1112 jobs_that_need_sessions++;
dcace88f 1113 } else if (launch_data_get_type(existing_v) == LAUNCH_DATA_OPAQUE) {
ddbbfbc1
A
1114 jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
1115 }
1116 }
1117 }
dcace88f 1118 } else if (v && launch_data_get_type(v) == LAUNCH_DATA_DICTIONARY) {
ddbbfbc1 1119 launch_data_t existing_v = launch_data_dict_lookup(v, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
dcace88f 1120 if (!existing_v) {
ddbbfbc1
A
1121 uuid_generate(uuid);
1122 uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
1123 launch_data_dict_insert(v, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
1124 jobs_that_need_sessions++;
1125 } else {
1126 jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
1127 }
1128 }
1129 }
1130#endif
1131
95379394 1132 pthread_mutex_lock(&globals->lc_mtx);
e91b9f68 1133
95379394 1134 if (d && launchd_msg_send(globals->l, d) == -1) {
e91b9f68 1135 do {
ed34e3c3 1136 if (errno != EAGAIN)
e91b9f68 1137 goto out;
95379394 1138 } while (launchd_msg_send(globals->l, NULL) == -1);
e91b9f68 1139 }
eabd1701 1140
e91b9f68 1141 while (resp == NULL) {
95379394
A
1142 if (d == NULL && launch_data_array_get_count(globals->async_resp) > 0) {
1143 resp = launch_data_array_pop_first(globals->async_resp);
e91b9f68
A
1144 goto out;
1145 }
95379394 1146 if (launchd_msg_recv(globals->l, launch_msg_getmsgs, &resp) == -1) {
ed34e3c3 1147 if (errno != EAGAIN) {
e91b9f68
A
1148 goto out;
1149 } else if (d == NULL) {
1150 errno = 0;
1151 goto out;
1152 } else {
1153 fd_set rfds;
1154
1155 FD_ZERO(&rfds);
ddbbfbc1 1156 FD_SET(fd2use, &rfds);
eabd1701 1157
ddbbfbc1 1158 select(fd2use + 1, &rfds, NULL, NULL, NULL);
e91b9f68
A
1159 }
1160 }
1161 }
1162
1163out:
ddbbfbc1 1164#if !TARGET_OS_EMBEDDED
dcace88f 1165 if (!uuid_is_null(uuid) && resp && jobs_that_need_sessions > 0) {
ddbbfbc1
A
1166 mach_port_t session_port = _audit_session_self();
1167 launch_data_type_t resp_type = launch_data_get_type(resp);
eabd1701 1168
ddbbfbc1 1169 bool set_session = false;
dcace88f 1170 if (resp_type == LAUNCH_DATA_ERRNO) {
eabd1701 1171 set_session = (launch_data_get_errno(resp) == ENEEDAUTH);
dcace88f 1172 } else if (resp_type == LAUNCH_DATA_ARRAY) {
ddbbfbc1
A
1173 set_session = true;
1174 }
eabd1701 1175
ddbbfbc1 1176 kern_return_t kr = KERN_FAILURE;
dcace88f 1177 if (set_session) {
ddbbfbc1
A
1178 kr = vproc_mig_set_security_session(bootstrap_port, uuid, session_port);
1179 }
eabd1701 1180
dcace88f
A
1181 if (kr == KERN_SUCCESS) {
1182 if (resp_type == LAUNCH_DATA_ERRNO) {
ddbbfbc1
A
1183 launch_data_set_errno(resp, 0);
1184 } else {
1185 size_t i = 0;
dcace88f 1186 for (i = 0; i < launch_data_array_get_count(resp); i++) {
ddbbfbc1 1187 launch_data_t ri = launch_data_array_get_index(resp, i);
eabd1701 1188
ddbbfbc1 1189 int recvd_err = 0;
dcace88f 1190 if (launch_data_get_type(ri) == LAUNCH_DATA_ERRNO && (recvd_err = launch_data_get_errno(ri))) {
ddbbfbc1
A
1191 launch_data_set_errno(ri, recvd_err == ENEEDAUTH ? 0 : recvd_err);
1192 }
1193 }
1194 }
1195 }
1196
1197 mach_port_deallocate(mach_task_self(), session_port);
1198 }
1199#endif
1200
95379394 1201 pthread_mutex_unlock(&globals->lc_mtx);
e91b9f68
A
1202
1203 return resp;
1204}
1205
ddbbfbc1
A
1206int
1207launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
e91b9f68
A
1208{
1209 struct cmsghdr *cm = alloca(4096);
aa59983a 1210 launch_data_t rmsg = NULL;
e91b9f68 1211 size_t data_offset, fd_offset;
5b0a4722
A
1212 struct msghdr mh;
1213 struct iovec iov;
e91b9f68
A
1214 int r;
1215
ddbbfbc1 1216 int fd2use = launchd_getfd(lh);
dcace88f 1217 if (fd2use == -1) {
ddbbfbc1
A
1218 errno = EPERM;
1219 return -1;
1220 }
1221
5b0a4722
A
1222 memset(&mh, 0, sizeof(mh));
1223 mh.msg_iov = &iov;
1224 mh.msg_iovlen = 1;
e91b9f68 1225
5b0a4722 1226 lh->recvbuf = reallocf(lh->recvbuf, lh->recvlen + 8*1024);
e91b9f68
A
1227
1228 iov.iov_base = lh->recvbuf + lh->recvlen;
1229 iov.iov_len = 8*1024;
1230 mh.msg_control = cm;
1231 mh.msg_controllen = 4096;
1232
ddbbfbc1 1233 if ((r = recvmsg(fd2use, &mh, 0)) == -1)
e91b9f68
A
1234 return -1;
1235 if (r == 0) {
1236 errno = ECONNRESET;
1237 return -1;
1238 }
ed34e3c3 1239 if (mh.msg_flags & MSG_CTRUNC) {
e91b9f68
A
1240 errno = ECONNABORTED;
1241 return -1;
1242 }
1243 lh->recvlen += r;
1244 if (mh.msg_controllen > 0) {
5b0a4722 1245 lh->recvfds = reallocf(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr));
e91b9f68
A
1246 memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr));
1247 lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
1248 }
1249
aa59983a
A
1250 r = 0;
1251
1252 while (lh->recvlen > 0) {
1253 struct launch_msg_header *lmhp = lh->recvbuf;
1254 uint64_t tmplen;
1255 data_offset = sizeof(struct launch_msg_header);
1256 fd_offset = 0;
1257
1258 if (lh->recvlen < sizeof(struct launch_msg_header))
1259 goto need_more_data;
1260
ddbbfbc1 1261 tmplen = big2wire(lmhp->len);
aa59983a 1262
ddbbfbc1 1263 if (big2wire(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) {
aa59983a
A
1264 errno = EBADRPC;
1265 goto out_bad;
1266 }
1267
1268 if (lh->recvlen < tmplen) {
1269 goto need_more_data;
1270 }
e91b9f68 1271
5b0a4722 1272 if ((rmsg = launch_data_unpack(lh->recvbuf, lh->recvlen, lh->recvfds, lh->recvfdcnt, &data_offset, &fd_offset)) == NULL) {
aa59983a
A
1273 errno = EBADRPC;
1274 goto out_bad;
1275 }
e91b9f68 1276
95379394
A
1277 launch_globals_t globals = _launch_globals();
1278
1279 globals->in_flight_msg_recv_client = lh;
f36da725 1280
e91b9f68
A
1281 cb(rmsg, context);
1282
f36da725 1283 /* launchd and only launchd can call launchd_close() as a part of the callback */
95379394 1284 if (globals->in_flight_msg_recv_client == NULL) {
f36da725
A
1285 r = 0;
1286 break;
1287 }
1288
e91b9f68
A
1289 lh->recvlen -= data_offset;
1290 if (lh->recvlen > 0) {
1291 memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen);
1292 } else {
1293 free(lh->recvbuf);
1294 lh->recvbuf = malloc(0);
1295 }
1296
1297 lh->recvfdcnt -= fd_offset;
1298 if (lh->recvfdcnt > 0) {
1299 memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int));
1300 } else {
1301 free(lh->recvfds);
1302 lh->recvfds = malloc(0);
1303 }
e91b9f68
A
1304 }
1305
1306 return r;
aa59983a
A
1307
1308need_more_data:
1309 errno = EAGAIN;
1310out_bad:
1311 return -1;
e91b9f68
A
1312}
1313
ddbbfbc1
A
1314launch_data_t
1315launch_data_copy(launch_data_t o)
e91b9f68
A
1316{
1317 launch_data_t r = launch_data_alloc(o->type);
1318 size_t i;
1319
1320 free(r->_array);
1321 memcpy(r, o, sizeof(struct _launch_data));
1322
1323 switch (o->type) {
1324 case LAUNCH_DATA_DICTIONARY:
1325 case LAUNCH_DATA_ARRAY:
1326 r->_array = calloc(1, o->_array_cnt * sizeof(launch_data_t));
1327 for (i = 0; i < o->_array_cnt; i++) {
1328 if (o->_array[i])
1329 r->_array[i] = launch_data_copy(o->_array[i]);
1330 }
1331 break;
1332 case LAUNCH_DATA_STRING:
1333 r->string = strdup(o->string);
1334 break;
1335 case LAUNCH_DATA_OPAQUE:
1336 r->opaque = malloc(o->opaque_size);
1337 memcpy(r->opaque, o->opaque, o->opaque_size);
1338 break;
1339 default:
1340 break;
1341 }
1342
1343 return r;
1344}
1345
ddbbfbc1
A
1346int
1347_fd(int fd)
e91b9f68
A
1348{
1349 if (fd >= 0)
ed34e3c3 1350 fcntl(fd, F_SETFD, 1);
e91b9f68
A
1351 return fd;
1352}
1353
ddbbfbc1
A
1354launch_data_t
1355launch_data_new_errno(int e)
e91b9f68
A
1356{
1357 launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
1358
1359 if (r)
5b0a4722 1360 launch_data_set_errno(r, e);
e91b9f68
A
1361
1362 return r;
1363}
1364
ddbbfbc1
A
1365launch_data_t
1366launch_data_new_fd(int fd)
e91b9f68
A
1367{
1368 launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
1369
1370 if (r)
5b0a4722 1371 launch_data_set_fd(r, fd);
e91b9f68
A
1372
1373 return r;
1374}
1375
ddbbfbc1
A
1376launch_data_t
1377launch_data_new_machport(mach_port_t p)
ed34e3c3
A
1378{
1379 launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT);
1380
1381 if (r)
5b0a4722 1382 launch_data_set_machport(r, p);
ed34e3c3
A
1383
1384 return r;
1385}
1386
ddbbfbc1
A
1387launch_data_t
1388launch_data_new_integer(long long n)
e91b9f68
A
1389{
1390 launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER);
1391
1392 if (r)
1393 launch_data_set_integer(r, n);
1394
1395 return r;
1396}
1397
ddbbfbc1
A
1398launch_data_t
1399launch_data_new_bool(bool b)
e91b9f68
A
1400{
1401 launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL);
1402
1403 if (r)
1404 launch_data_set_bool(r, b);
1405
1406 return r;
1407}
1408
ddbbfbc1
A
1409launch_data_t
1410launch_data_new_real(double d)
e91b9f68
A
1411{
1412 launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL);
1413
1414 if (r)
1415 launch_data_set_real(r, d);
1416
1417 return r;
1418}
1419
ddbbfbc1
A
1420launch_data_t
1421launch_data_new_string(const char *s)
e91b9f68
A
1422{
1423 launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING);
1424
1425 if (r == NULL)
1426 return NULL;
1427
1428 if (!launch_data_set_string(r, s)) {
1429 launch_data_free(r);
1430 return NULL;
1431 }
1432
1433 return r;
1434}
1435
ddbbfbc1
A
1436launch_data_t
1437launch_data_new_opaque(const void *o, size_t os)
e91b9f68
A
1438{
1439 launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
1440
1441 if (r == NULL)
1442 return NULL;
1443
1444 if (!launch_data_set_opaque(r, o, os)) {
1445 launch_data_free(r);
1446 return NULL;
1447 }
1448
1449 return r;
1450}
ed34e3c3 1451
5b0a4722
A
1452void
1453load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...)
ed34e3c3 1454{
ddbbfbc1 1455 _vprocmgr_init(VPROCMGR_SESSION_LOGINWINDOW);
ed34e3c3
A
1456}
1457
1458pid_t
ddbbfbc1 1459create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags, ...)
ed34e3c3 1460{
5b0a4722 1461 uid_t target_user = geteuid() ? geteuid() : getuid();
ddbbfbc1 1462 if (_vprocmgr_move_subset_to_user(target_user, VPROCMGR_SESSION_AQUA, flags)) {
ed34e3c3 1463 return -1;
5b0a4722 1464 }
ed34e3c3 1465
5b0a4722 1466 return 1;
ed34e3c3 1467}