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