]> git.saurik.com Git - apple/launchd.git/blob - launchd/src/liblaunch.c
ceebfef1f78a4c45df071bda828fe9d51e94bdf0
[apple/launchd.git] / launchd / src / liblaunch.c
1 /*
2 * Copyright (c) 2005 Apple Computer, 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 #include <mach/mach.h>
21 #include <libkern/OSByteOrder.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/fcntl.h>
25 #include <sys/un.h>
26 #include <sys/uio.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <pwd.h>
35
36 #include "launch.h"
37 #include "launch_priv.h"
38 #include "bootstrap_public.h"
39 #include "bootstrap_private.h"
40
41 /* __OSBogusByteSwap__() must not really exist in the symbol namespace
42 * in order for the following to generate an error at build time.
43 */
44 extern void __OSBogusByteSwap__(void);
45
46 #define host2big(x) \
47 ({ typeof (x) _X, _x = (x); \
48 switch (sizeof(_x)) { \
49 case 8: \
50 _X = OSSwapHostToBigInt64(_x); \
51 break; \
52 case 4: \
53 _X = OSSwapHostToBigInt32(_x); \
54 break; \
55 case 2: \
56 _X = OSSwapHostToBigInt16(_x); \
57 break; \
58 case 1: \
59 _X = _x; \
60 break; \
61 default: \
62 __OSBogusByteSwap__(); \
63 break; \
64 } \
65 _X; \
66 })
67
68
69 #define big2host(x) \
70 ({ typeof (x) _X, _x = (x); \
71 switch (sizeof(_x)) { \
72 case 8: \
73 _X = OSSwapBigToHostInt64(_x); \
74 break; \
75 case 4: \
76 _X = OSSwapBigToHostInt32(_x); \
77 break; \
78 case 2: \
79 _X = OSSwapBigToHostInt16(_x); \
80 break; \
81 case 1: \
82 _X = _x; \
83 break; \
84 default: \
85 __OSBogusByteSwap__(); \
86 break; \
87 } \
88 _X; \
89 })
90
91
92 struct launch_msg_header {
93 uint64_t magic;
94 uint64_t len;
95 };
96
97 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
98
99 struct _launch_data {
100 uint64_t type;
101 union {
102 struct {
103 union {
104 launch_data_t *_array;
105 char *string;
106 void *opaque;
107 int64_t __junk;
108 };
109 union {
110 uint64_t _array_cnt;
111 uint64_t string_len;
112 uint64_t opaque_size;
113 };
114 };
115 int fd;
116 mach_port_t mp;
117 int err;
118 long long number;
119 bool boolean;
120 double float_num;
121 };
122 };
123
124 struct _launch {
125 void *sendbuf;
126 int *sendfds;
127 void *recvbuf;
128 int *recvfds;
129 size_t sendlen;
130 size_t sendfdcnt;
131 size_t recvlen;
132 size_t recvfdcnt;
133 int fd;
134 };
135
136 static void make_msg_and_cmsg(launch_data_t, void **, size_t *, int **, size_t *);
137 static launch_data_t make_data(launch_t, size_t *, size_t *);
138 static launch_data_t launch_data_array_pop_first(launch_data_t where);
139 static int _fd(int fd);
140 static void launch_client_init(void);
141 static void launch_msg_getmsgs(launch_data_t m, void *context);
142 static launch_data_t launch_msg_internal(launch_data_t d);
143 static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
144
145 static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
146
147 static struct _launch_client {
148 pthread_mutex_t mtx;
149 launch_t l;
150 launch_data_t async_resp;
151 } *_lc = NULL;
152
153 void
154 launch_client_init(void)
155 {
156 struct sockaddr_un sun;
157 char *where = getenv(LAUNCHD_SOCKET_ENV);
158 char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
159 int dfd, lfd = -1;
160
161 _lc = calloc(1, sizeof(struct _launch_client));
162
163 if (!_lc)
164 return;
165
166 pthread_mutex_init(&_lc->mtx, NULL);
167
168 if (_launchd_fd) {
169 lfd = strtol(_launchd_fd, NULL, 10);
170 if ((dfd = dup(lfd)) >= 0) {
171 close(dfd);
172 _fd(lfd);
173 } else {
174 lfd = -1;
175 }
176 unsetenv(LAUNCHD_TRUSTED_FD_ENV);
177 }
178 if (lfd == -1) {
179 memset(&sun, 0, sizeof(sun));
180 sun.sun_family = AF_UNIX;
181
182 if (where && where[0] != '\0') {
183 strncpy(sun.sun_path, where, sizeof(sun.sun_path));
184 } else if (getuid() == 0) {
185 strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
186 } else {
187 goto out_bad;
188 }
189
190 if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1)
191 goto out_bad;
192 if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun)))
193 goto out_bad;
194 }
195 if (!(_lc->l = launchd_fdopen(lfd)))
196 goto out_bad;
197 if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY)))
198 goto out_bad;
199
200 return;
201 out_bad:
202 if (_lc->l)
203 launchd_close(_lc->l);
204 else if (lfd != -1)
205 close(lfd);
206 if (_lc)
207 free(_lc);
208 _lc = NULL;
209 }
210
211 launch_data_t
212 launch_data_alloc(launch_data_type_t t)
213 {
214 launch_data_t d = calloc(1, sizeof(struct _launch));
215
216 if (d) {
217 d->type = t;
218 switch (t) {
219 case LAUNCH_DATA_DICTIONARY:
220 case LAUNCH_DATA_ARRAY:
221 d->_array = malloc(0);
222 break;
223 default:
224 break;
225 }
226 }
227
228 return d;
229 }
230
231 launch_data_type_t
232 launch_data_get_type(launch_data_t d)
233 {
234 return d->type;
235 }
236
237 void
238 launch_data_free(launch_data_t d)
239 {
240 size_t i;
241
242 switch (d->type) {
243 case LAUNCH_DATA_DICTIONARY:
244 case LAUNCH_DATA_ARRAY:
245 for (i = 0; i < d->_array_cnt; i++)
246 launch_data_free(d->_array[i]);
247 free(d->_array);
248 break;
249 case LAUNCH_DATA_STRING:
250 if (d->string)
251 free(d->string);
252 break;
253 case LAUNCH_DATA_OPAQUE:
254 if (d->opaque)
255 free(d->opaque);
256 break;
257 default:
258 break;
259 }
260 free(d);
261 }
262
263 size_t
264 launch_data_dict_get_count(launch_data_t dict)
265 {
266 return dict->_array_cnt / 2;
267 }
268
269
270 bool
271 launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
272 {
273 size_t i;
274 launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING);
275
276 launch_data_set_string(thekey, key);
277
278 for (i = 0; i < dict->_array_cnt; i += 2) {
279 if (!strcasecmp(key, dict->_array[i]->string)) {
280 launch_data_array_set_index(dict, thekey, i);
281 launch_data_array_set_index(dict, what, i + 1);
282 return true;
283 }
284 }
285 launch_data_array_set_index(dict, thekey, i);
286 launch_data_array_set_index(dict, what, i + 1);
287 return true;
288 }
289
290 launch_data_t
291 launch_data_dict_lookup(launch_data_t dict, const char *key)
292 {
293 size_t i;
294
295 if (LAUNCH_DATA_DICTIONARY != dict->type)
296 return NULL;
297
298 for (i = 0; i < dict->_array_cnt; i += 2) {
299 if (!strcasecmp(key, dict->_array[i]->string))
300 return dict->_array[i + 1];
301 }
302
303 return NULL;
304 }
305
306 bool
307 launch_data_dict_remove(launch_data_t dict, const char *key)
308 {
309 size_t i;
310
311 for (i = 0; i < dict->_array_cnt; i += 2) {
312 if (!strcasecmp(key, dict->_array[i]->string))
313 break;
314 }
315 if (i == dict->_array_cnt)
316 return false;
317 launch_data_free(dict->_array[i]);
318 launch_data_free(dict->_array[i + 1]);
319 memmove(dict->_array + i, dict->_array + i + 2, (dict->_array_cnt - (i + 2)) * sizeof(launch_data_t));
320 dict->_array_cnt -= 2;
321 return true;
322 }
323
324 void
325 launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
326 {
327 size_t i;
328
329 if (LAUNCH_DATA_DICTIONARY != dict->type)
330 return;
331
332 for (i = 0; i < dict->_array_cnt; i += 2)
333 cb(dict->_array[i + 1], dict->_array[i]->string, context);
334 }
335
336 bool
337 launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
338 {
339 if ((ind + 1) >= where->_array_cnt) {
340 where->_array = realloc(where->_array, (ind + 1) * sizeof(launch_data_t));
341 memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t));
342 where->_array_cnt = ind + 1;
343 }
344
345 if (where->_array[ind])
346 launch_data_free(where->_array[ind]);
347 where->_array[ind] = what;
348 return true;
349 }
350
351 launch_data_t
352 launch_data_array_get_index(launch_data_t where, size_t ind)
353 {
354 if (LAUNCH_DATA_ARRAY != where->type)
355 return NULL;
356 if (ind < where->_array_cnt)
357 return where->_array[ind];
358 return NULL;
359 }
360
361 launch_data_t
362 launch_data_array_pop_first(launch_data_t where)
363 {
364 launch_data_t r = NULL;
365
366 if (where->_array_cnt > 0) {
367 r = where->_array[0];
368 memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t));
369 where->_array_cnt--;
370 }
371 return r;
372 }
373
374 size_t
375 launch_data_array_get_count(launch_data_t where)
376 {
377 if (LAUNCH_DATA_ARRAY != where->type)
378 return 0;
379 return where->_array_cnt;
380 }
381
382 bool
383 launch_data_set_errno(launch_data_t d, int e)
384 {
385 d->err = e;
386 return true;
387 }
388
389 bool
390 launch_data_set_fd(launch_data_t d, int fd)
391 {
392 d->fd = fd;
393 return true;
394 }
395
396 bool
397 launch_data_set_machport(launch_data_t d, mach_port_t p)
398 {
399 d->mp = p;
400 return true;
401 }
402
403 bool
404 launch_data_set_integer(launch_data_t d, long long n)
405 {
406 d->number = n;
407 return true;
408 }
409
410 bool
411 launch_data_set_bool(launch_data_t d, bool b)
412 {
413 d->boolean = b;
414 return true;
415 }
416
417 bool
418 launch_data_set_real(launch_data_t d, double n)
419 {
420 d->float_num = n;
421 return true;
422 }
423
424 bool
425 launch_data_set_string(launch_data_t d, const char *s)
426 {
427 if (d->string)
428 free(d->string);
429 d->string = strdup(s);
430 if (d->string) {
431 d->string_len = strlen(d->string);
432 return true;
433 }
434 return false;
435 }
436
437 bool
438 launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
439 {
440 d->opaque_size = os;
441 if (d->opaque)
442 free(d->opaque);
443 d->opaque = malloc(os);
444 if (d->opaque) {
445 memcpy(d->opaque, o, os);
446 return true;
447 }
448 return false;
449 }
450
451 int
452 launch_data_get_errno(launch_data_t d)
453 {
454 return d->err;
455 }
456
457 int
458 launch_data_get_fd(launch_data_t d)
459 {
460 return d->fd;
461 }
462
463 mach_port_t
464 launch_data_get_machport(launch_data_t d)
465 {
466 return d->mp;
467 }
468
469 long long
470 launch_data_get_integer(launch_data_t d)
471 {
472 return d->number;
473 }
474
475 bool
476 launch_data_get_bool(launch_data_t d)
477 {
478 return d->boolean;
479 }
480
481 double
482 launch_data_get_real(launch_data_t d)
483 {
484 return d->float_num;
485 }
486
487 const char *
488 launch_data_get_string(launch_data_t d)
489 {
490 if (LAUNCH_DATA_STRING != d->type)
491 return NULL;
492 return d->string;
493 }
494
495 void *
496 launch_data_get_opaque(launch_data_t d)
497 {
498 if (LAUNCH_DATA_OPAQUE != d->type)
499 return NULL;
500 return d->opaque;
501 }
502
503 size_t
504 launch_data_get_opaque_size(launch_data_t d)
505 {
506 return d->opaque_size;
507 }
508
509 int
510 launchd_getfd(launch_t l)
511 {
512 return l->fd;
513 }
514
515 launch_t
516 launchd_fdopen(int fd)
517 {
518 launch_t c;
519
520 c = calloc(1, sizeof(struct _launch));
521 if (!c)
522 return NULL;
523
524 c->fd = fd;
525
526 fcntl(fd, F_SETFL, O_NONBLOCK);
527
528 if ((c->sendbuf = malloc(0)) == NULL)
529 goto out_bad;
530 if ((c->sendfds = malloc(0)) == NULL)
531 goto out_bad;
532 if ((c->recvbuf = malloc(0)) == NULL)
533 goto out_bad;
534 if ((c->recvfds = malloc(0)) == NULL)
535 goto out_bad;
536
537 return c;
538
539 out_bad:
540 if (c->sendbuf)
541 free(c->sendbuf);
542 if (c->sendfds)
543 free(c->sendfds);
544 if (c->recvbuf)
545 free(c->recvbuf);
546 if (c->recvfds)
547 free(c->recvfds);
548 free(c);
549 return NULL;
550 }
551
552 void
553 launchd_close(launch_t lh)
554 {
555 if (lh->sendbuf)
556 free(lh->sendbuf);
557 if (lh->sendfds)
558 free(lh->sendfds);
559 if (lh->recvbuf)
560 free(lh->recvbuf);
561 if (lh->recvfds)
562 free(lh->recvfds);
563 close(lh->fd);
564 free(lh);
565 }
566
567 void
568 make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int **fd_where, size_t *fdcnt)
569 {
570 launch_data_t o_in_w;
571 size_t i;
572
573 *where = realloc(*where, *len + sizeof(struct _launch_data));
574
575 o_in_w = *where + *len;
576 memset(o_in_w, 0, sizeof(struct _launch_data));
577 *len += sizeof(struct _launch_data);
578
579 o_in_w->type = host2big(d->type);
580
581 switch (d->type) {
582 case LAUNCH_DATA_INTEGER:
583 o_in_w->number = host2big(d->number);
584 break;
585 case LAUNCH_DATA_REAL:
586 o_in_w->float_num = host2big(d->float_num);
587 break;
588 case LAUNCH_DATA_BOOL:
589 o_in_w->boolean = host2big(d->boolean);
590 break;
591 case LAUNCH_DATA_ERRNO:
592 o_in_w->err = host2big(d->err);
593 break;
594 case LAUNCH_DATA_FD:
595 o_in_w->fd = host2big(d->fd);
596 if (d->fd != -1) {
597 *fd_where = realloc(*fd_where, (*fdcnt + 1) * sizeof(int));
598 (*fd_where)[*fdcnt] = d->fd;
599 (*fdcnt)++;
600 }
601 break;
602 case LAUNCH_DATA_STRING:
603 o_in_w->string_len = host2big(d->string_len);
604 *where = realloc(*where, *len + strlen(d->string) + 1);
605 memcpy(*where + *len, d->string, strlen(d->string) + 1);
606 *len += strlen(d->string) + 1;
607 break;
608 case LAUNCH_DATA_OPAQUE:
609 o_in_w->opaque_size = host2big(d->opaque_size);
610 *where = realloc(*where, *len + d->opaque_size);
611 memcpy(*where + *len, d->opaque, d->opaque_size);
612 *len += d->opaque_size;
613 break;
614 case LAUNCH_DATA_DICTIONARY:
615 case LAUNCH_DATA_ARRAY:
616 o_in_w->_array_cnt = host2big(d->_array_cnt);
617 *where = realloc(*where, *len + (d->_array_cnt * sizeof(launch_data_t)));
618 memcpy(*where + *len, d->_array, d->_array_cnt * sizeof(launch_data_t));
619 *len += d->_array_cnt * sizeof(launch_data_t);
620
621 for (i = 0; i < d->_array_cnt; i++)
622 make_msg_and_cmsg(d->_array[i], where, len, fd_where, fdcnt);
623 break;
624 default:
625 break;
626 }
627 }
628
629 static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoffset)
630 {
631 launch_data_t r = conn->recvbuf + *data_offset;
632 size_t i, tmpcnt;
633
634 if ((conn->recvlen - *data_offset) < sizeof(struct _launch_data))
635 return NULL;
636 *data_offset += sizeof(struct _launch_data);
637
638 switch (big2host(r->type)) {
639 case LAUNCH_DATA_DICTIONARY:
640 case LAUNCH_DATA_ARRAY:
641 tmpcnt = big2host(r->_array_cnt);
642 if ((conn->recvlen - *data_offset) < (tmpcnt * sizeof(launch_data_t))) {
643 errno = EAGAIN;
644 return NULL;
645 }
646 r->_array = conn->recvbuf + *data_offset;
647 *data_offset += tmpcnt * sizeof(launch_data_t);
648 for (i = 0; i < tmpcnt; i++) {
649 r->_array[i] = make_data(conn, data_offset, fdoffset);
650 if (r->_array[i] == NULL)
651 return NULL;
652 }
653 r->_array_cnt = tmpcnt;
654 break;
655 case LAUNCH_DATA_STRING:
656 tmpcnt = big2host(r->string_len);
657 if ((conn->recvlen - *data_offset) < (tmpcnt + 1)) {
658 errno = EAGAIN;
659 return NULL;
660 }
661 r->string = conn->recvbuf + *data_offset;
662 r->string_len = tmpcnt;
663 *data_offset += tmpcnt + 1;
664 break;
665 case LAUNCH_DATA_OPAQUE:
666 tmpcnt = big2host(r->opaque_size);
667 if ((conn->recvlen - *data_offset) < tmpcnt) {
668 errno = EAGAIN;
669 return NULL;
670 }
671 r->opaque = conn->recvbuf + *data_offset;
672 r->opaque_size = tmpcnt;
673 *data_offset += tmpcnt;
674 break;
675 case LAUNCH_DATA_FD:
676 if (r->fd != -1) {
677 r->fd = _fd(conn->recvfds[*fdoffset]);
678 *fdoffset += 1;
679 }
680 break;
681 case LAUNCH_DATA_INTEGER:
682 r->number = big2host(r->number);
683 break;
684 case LAUNCH_DATA_REAL:
685 r->float_num = big2host(r->float_num);
686 break;
687 case LAUNCH_DATA_BOOL:
688 r->boolean = big2host(r->boolean);
689 break;
690 case LAUNCH_DATA_ERRNO:
691 r->err = big2host(r->err);
692 case LAUNCH_DATA_MACHPORT:
693 break;
694 default:
695 errno = EINVAL;
696 return NULL;
697 break;
698 }
699
700 r->type = big2host(r->type);
701
702 return r;
703 }
704
705 int launchd_msg_send(launch_t lh, launch_data_t d)
706 {
707 struct launch_msg_header lmh;
708 struct cmsghdr *cm = NULL;
709 struct msghdr mh;
710 struct iovec iov[2];
711 size_t sentctrllen = 0;
712 int r;
713
714 memset(&mh, 0, sizeof(mh));
715
716 if (d) {
717 uint64_t msglen = lh->sendlen;
718
719 make_msg_and_cmsg(d, &lh->sendbuf, &lh->sendlen, &lh->sendfds, &lh->sendfdcnt);
720
721 msglen = (lh->sendlen - msglen) + sizeof(struct launch_msg_header);
722 lmh.len = host2big(msglen);
723 lmh.magic = host2big(LAUNCH_MSG_HEADER_MAGIC);
724
725 iov[0].iov_base = &lmh;
726 iov[0].iov_len = sizeof(lmh);
727 mh.msg_iov = iov;
728 mh.msg_iovlen = 2;
729 } else {
730 mh.msg_iov = iov + 1;
731 mh.msg_iovlen = 1;
732 }
733
734 iov[1].iov_base = lh->sendbuf;
735 iov[1].iov_len = lh->sendlen;
736
737
738 if (lh->sendfdcnt > 0) {
739 sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int));
740 cm = alloca(mh.msg_controllen);
741 mh.msg_control = cm;
742
743 memset(cm, 0, mh.msg_controllen);
744
745 cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int));
746 cm->cmsg_level = SOL_SOCKET;
747 cm->cmsg_type = SCM_RIGHTS;
748
749 memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int));
750 }
751
752 if ((r = sendmsg(lh->fd, &mh, 0)) == -1) {
753 return -1;
754 } else if (r == 0) {
755 errno = ECONNRESET;
756 return -1;
757 } else if (sentctrllen != mh.msg_controllen) {
758 errno = ECONNRESET;
759 return -1;
760 }
761
762 if (d) {
763 r -= sizeof(struct launch_msg_header);
764 }
765
766 lh->sendlen -= r;
767 if (lh->sendlen > 0) {
768 memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen);
769 } else {
770 free(lh->sendbuf);
771 lh->sendbuf = malloc(0);
772 }
773
774 lh->sendfdcnt = 0;
775 free(lh->sendfds);
776 lh->sendfds = malloc(0);
777
778 if (lh->sendlen > 0) {
779 errno = EAGAIN;
780 return -1;
781 }
782
783 return 0;
784 }
785
786
787 int
788 launch_get_fd(void)
789 {
790 pthread_once(&_lc_once, launch_client_init);
791
792 if (!_lc) {
793 errno = ENOTCONN;
794 return -1;
795 }
796
797 return _lc->l->fd;
798 }
799
800 void
801 launch_msg_getmsgs(launch_data_t m, void *context)
802 {
803 launch_data_t async_resp, *sync_resp = context;
804
805 if ((LAUNCH_DATA_DICTIONARY == launch_data_get_type(m)) && (async_resp = launch_data_dict_lookup(m, LAUNCHD_ASYNC_MSG_KEY))) {
806 launch_data_array_set_index(_lc->async_resp, launch_data_copy(async_resp), launch_data_array_get_count(_lc->async_resp));
807 } else {
808 *sync_resp = launch_data_copy(m);
809 }
810 }
811
812 void
813 launch_mach_checkin_service(launch_data_t obj, const char *key, void *context __attribute__((unused)))
814 {
815 kern_return_t result;
816 mach_port_t p;
817 name_t srvnm;
818
819 strlcpy(srvnm, key, sizeof(srvnm));
820
821 result = bootstrap_check_in(bootstrap_port, srvnm, &p);
822
823 if (result == BOOTSTRAP_SUCCESS)
824 launch_data_set_machport(obj, p);
825 }
826
827 launch_data_t
828 launch_msg(launch_data_t d)
829 {
830 launch_data_t mps, r = launch_msg_internal(d);
831
832 if (launch_data_get_type(d) == LAUNCH_DATA_STRING) {
833 if (strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) != 0)
834 return r;
835 if (r == NULL)
836 return r;
837 if (launch_data_get_type(r) != LAUNCH_DATA_DICTIONARY)
838 return r;
839 mps = launch_data_dict_lookup(r, LAUNCH_JOBKEY_MACHSERVICES);
840 if (mps == NULL)
841 return r;
842 launch_data_dict_iterate(mps, launch_mach_checkin_service, NULL);
843 }
844
845 return r;
846 }
847
848 launch_data_t
849 launch_msg_internal(launch_data_t d)
850 {
851 launch_data_t resp = NULL;
852
853 pthread_once(&_lc_once, launch_client_init);
854
855 if (!_lc) {
856 errno = ENOTCONN;
857 return NULL;
858 }
859
860 pthread_mutex_lock(&_lc->mtx);
861
862 if (d && launchd_msg_send(_lc->l, d) == -1) {
863 do {
864 if (errno != EAGAIN)
865 goto out;
866 } while (launchd_msg_send(_lc->l, NULL) == -1);
867 }
868
869 while (resp == NULL) {
870 if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) {
871 resp = launch_data_array_pop_first(_lc->async_resp);
872 goto out;
873 }
874 if (launchd_msg_recv(_lc->l, launch_msg_getmsgs, &resp) == -1) {
875 if (errno != EAGAIN) {
876 goto out;
877 } else if (d == NULL) {
878 errno = 0;
879 goto out;
880 } else {
881 fd_set rfds;
882
883 FD_ZERO(&rfds);
884 FD_SET(_lc->l->fd, &rfds);
885
886 select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL);
887 }
888 }
889 }
890
891 out:
892 pthread_mutex_unlock(&_lc->mtx);
893
894 return resp;
895 }
896
897 int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
898 {
899 struct cmsghdr *cm = alloca(4096);
900 launch_data_t rmsg = NULL;
901 size_t data_offset, fd_offset;
902 struct msghdr mh;
903 struct iovec iov;
904 int r;
905
906 memset(&mh, 0, sizeof(mh));
907 mh.msg_iov = &iov;
908 mh.msg_iovlen = 1;
909
910 lh->recvbuf = realloc(lh->recvbuf, lh->recvlen + 8*1024);
911
912 iov.iov_base = lh->recvbuf + lh->recvlen;
913 iov.iov_len = 8*1024;
914 mh.msg_control = cm;
915 mh.msg_controllen = 4096;
916
917 if ((r = recvmsg(lh->fd, &mh, 0)) == -1)
918 return -1;
919 if (r == 0) {
920 errno = ECONNRESET;
921 return -1;
922 }
923 if (mh.msg_flags & MSG_CTRUNC) {
924 errno = ECONNABORTED;
925 return -1;
926 }
927 lh->recvlen += r;
928 if (mh.msg_controllen > 0) {
929 lh->recvfds = realloc(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr));
930 memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr));
931 lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
932 }
933
934 r = 0;
935
936 while (lh->recvlen > 0) {
937 struct launch_msg_header *lmhp = lh->recvbuf;
938 uint64_t tmplen;
939 data_offset = sizeof(struct launch_msg_header);
940 fd_offset = 0;
941
942 if (lh->recvlen < sizeof(struct launch_msg_header))
943 goto need_more_data;
944
945 tmplen = big2host(lmhp->len);
946
947 if (big2host(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) {
948 errno = EBADRPC;
949 goto out_bad;
950 }
951
952 if (lh->recvlen < tmplen) {
953 goto need_more_data;
954 }
955
956 if ((rmsg = make_data(lh, &data_offset, &fd_offset)) == NULL) {
957 errno = EBADRPC;
958 goto out_bad;
959 }
960
961 cb(rmsg, context);
962
963 lh->recvlen -= data_offset;
964 if (lh->recvlen > 0) {
965 memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen);
966 } else {
967 free(lh->recvbuf);
968 lh->recvbuf = malloc(0);
969 }
970
971 lh->recvfdcnt -= fd_offset;
972 if (lh->recvfdcnt > 0) {
973 memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int));
974 } else {
975 free(lh->recvfds);
976 lh->recvfds = malloc(0);
977 }
978 }
979
980 return r;
981
982 need_more_data:
983 errno = EAGAIN;
984 out_bad:
985 return -1;
986 }
987
988 launch_data_t launch_data_copy(launch_data_t o)
989 {
990 launch_data_t r = launch_data_alloc(o->type);
991 size_t i;
992
993 free(r->_array);
994 memcpy(r, o, sizeof(struct _launch_data));
995
996 switch (o->type) {
997 case LAUNCH_DATA_DICTIONARY:
998 case LAUNCH_DATA_ARRAY:
999 r->_array = calloc(1, o->_array_cnt * sizeof(launch_data_t));
1000 for (i = 0; i < o->_array_cnt; i++) {
1001 if (o->_array[i])
1002 r->_array[i] = launch_data_copy(o->_array[i]);
1003 }
1004 break;
1005 case LAUNCH_DATA_STRING:
1006 r->string = strdup(o->string);
1007 break;
1008 case LAUNCH_DATA_OPAQUE:
1009 r->opaque = malloc(o->opaque_size);
1010 memcpy(r->opaque, o->opaque, o->opaque_size);
1011 break;
1012 default:
1013 break;
1014 }
1015
1016 return r;
1017 }
1018
1019 void launchd_batch_enable(bool val)
1020 {
1021 launch_data_t resp, tmp, msg;
1022
1023 tmp = launch_data_alloc(LAUNCH_DATA_BOOL);
1024 launch_data_set_bool(tmp, val);
1025
1026 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
1027 launch_data_dict_insert(msg, tmp, LAUNCH_KEY_BATCHCONTROL);
1028
1029 resp = launch_msg(msg);
1030
1031 launch_data_free(msg);
1032
1033 if (resp)
1034 launch_data_free(resp);
1035 }
1036
1037 bool launchd_batch_query(void)
1038 {
1039 launch_data_t resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
1040 bool rval = true;
1041
1042 launch_data_set_string(msg, LAUNCH_KEY_BATCHQUERY);
1043
1044 resp = launch_msg(msg);
1045
1046 launch_data_free(msg);
1047
1048 if (resp) {
1049 if (launch_data_get_type(resp) == LAUNCH_DATA_BOOL)
1050 rval = launch_data_get_bool(resp);
1051 launch_data_free(resp);
1052 }
1053 return rval;
1054 }
1055
1056 static int _fd(int fd)
1057 {
1058 if (fd >= 0)
1059 fcntl(fd, F_SETFD, 1);
1060 return fd;
1061 }
1062
1063 launch_data_t launch_data_new_errno(int e)
1064 {
1065 launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
1066
1067 if (r)
1068 launch_data_set_errno(r, e);
1069
1070 return r;
1071 }
1072
1073 launch_data_t launch_data_new_fd(int fd)
1074 {
1075 launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
1076
1077 if (r)
1078 launch_data_set_fd(r, fd);
1079
1080 return r;
1081 }
1082
1083 launch_data_t launch_data_new_machport(mach_port_t p)
1084 {
1085 launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT);
1086
1087 if (r)
1088 launch_data_set_machport(r, p);
1089
1090 return r;
1091 }
1092
1093 launch_data_t launch_data_new_integer(long long n)
1094 {
1095 launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER);
1096
1097 if (r)
1098 launch_data_set_integer(r, n);
1099
1100 return r;
1101 }
1102
1103 launch_data_t launch_data_new_bool(bool b)
1104 {
1105 launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL);
1106
1107 if (r)
1108 launch_data_set_bool(r, b);
1109
1110 return r;
1111 }
1112
1113 launch_data_t launch_data_new_real(double d)
1114 {
1115 launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL);
1116
1117 if (r)
1118 launch_data_set_real(r, d);
1119
1120 return r;
1121 }
1122
1123 launch_data_t launch_data_new_string(const char *s)
1124 {
1125 launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING);
1126
1127 if (r == NULL)
1128 return NULL;
1129
1130 if (!launch_data_set_string(r, s)) {
1131 launch_data_free(r);
1132 return NULL;
1133 }
1134
1135 return r;
1136 }
1137
1138 launch_data_t launch_data_new_opaque(const void *o, size_t os)
1139 {
1140 launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
1141
1142 if (r == NULL)
1143 return NULL;
1144
1145 if (!launch_data_set_opaque(r, o, os)) {
1146 launch_data_free(r);
1147 return NULL;
1148 }
1149
1150 return r;
1151 }
1152
1153 static pid_t
1154 fexecv_as_user(const char *login, uid_t u, gid_t g, char *const argv[])
1155 {
1156 int i, dtsz;
1157 pid_t p;
1158
1159 if ((p = fork()) != 0)
1160 return p;
1161
1162 chdir("/");
1163
1164 seteuid(0);
1165 setegid(0);
1166 initgroups(login, g);
1167 setgid(g);
1168 setuid(u);
1169
1170 dtsz = getdtablesize();
1171
1172 for (i = STDERR_FILENO + 1; i < dtsz; i++)
1173 close(i);
1174
1175 execv(argv[0], argv);
1176 _exit(EXIT_FAILURE);
1177 }
1178
1179 pid_t
1180 create_and_switch_to_per_session_launchd(const char *login, int flags, ...)
1181 {
1182 static char *const ldargv[] = { "/sbin/launchd", "-S", "Aqua", NULL };
1183 char *largv[] = { "/bin/launchctl", "load", "-S", "Aqua", "-D", "all", "/etc/mach_init_per_user.d", NULL };
1184 mach_port_t bezel_ui_server;
1185 struct passwd *pwe;
1186 struct stat sb;
1187 int wstatus;
1188 name_t sp;
1189 pid_t p, ldp;
1190 uid_t u;
1191 gid_t g;
1192
1193 if ((pwe = getpwnam(login)) == NULL)
1194 return -1;
1195
1196 u = pwe->pw_uid;
1197 g = pwe->pw_gid;
1198
1199 if ((ldp = fexecv_as_user(login, u, g, ldargv)) == -1)
1200 return -1;
1201
1202 while (bootstrap_getsocket(bootstrap_port, sp) != BOOTSTRAP_SUCCESS)
1203 usleep(20000);
1204
1205 setenv(LAUNCHD_SOCKET_ENV, sp, 1);
1206
1207 if (flags & LOAD_ONLY_SAFEMODE_LAUNCHAGENTS)
1208 largv[5] = "system";
1209
1210 if ((p = fexecv_as_user(login, u, g, largv)) == -1)
1211 return -1;
1212
1213 if (waitpid(p, &wstatus, 0) != p)
1214 return -1;
1215
1216 if (!(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0))
1217 return -1;
1218
1219 #define BEZEL_UI_PATH "/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/BezelUI/BezelUIServer"
1220 #define BEZEL_UI_PLIST "/System/Library/LaunchAgents/com.apple.BezelUIServer.plist"
1221 #define BEZEL_UI_SERVICE "BezelUI"
1222
1223 if (!(stat(BEZEL_UI_PLIST, &sb) == 0 && S_ISREG(sb.st_mode))) {
1224 if (bootstrap_create_server(bootstrap_port, BEZEL_UI_PATH, u, true, &bezel_ui_server) == BOOTSTRAP_SUCCESS) {
1225 mach_port_t srv;
1226
1227 if (bootstrap_create_service(bezel_ui_server, BEZEL_UI_SERVICE, &srv) == BOOTSTRAP_SUCCESS) {
1228 mach_port_deallocate(mach_task_self(), srv);
1229 }
1230
1231 mach_port_deallocate(mach_task_self(), bezel_ui_server);
1232 }
1233 }
1234
1235 return ldp;
1236 }