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