2 * Copyright (c) 2005-2012 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #include "launch_priv.h"
24 #include "launch_internal.h"
27 #include <mach/mach.h>
28 #include <libkern/OSByteOrder.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/fcntl.h>
43 #include <uuid/uuid.h>
44 #include <sys/syscall.h>
48 /* workaround: 5723161 */
49 #ifndef __DARWIN_ALIGN32
50 #define __DARWIN_ALIGN32(x) (((size_t)(x) + 3) & ~3)
53 #define CMSG_DATA(cmsg) \
54 ((uint8_t *)(cmsg) + __DARWIN_ALIGN32(sizeof(struct cmsghdr)))
56 #define CMSG_SPACE(l) \
57 (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + __DARWIN_ALIGN32(l))
60 (__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + (l))
68 launch_data_t
*_array
;
83 uint64_t boolean
; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
88 #include "bootstrap.h"
90 #include "vproc_priv.h"
91 #include "vproc_internal.h"
93 /* __OSBogusByteSwap__() must not really exist in the symbol namespace
94 * in order for the following to generate an error at build time.
96 extern void __OSBogusByteSwap__(void);
98 #define host2wire(x) \
99 ({ typeof (x) _X, _x = (x); \
100 switch (sizeof(_x)) { \
102 _X = OSSwapHostToLittleInt64(_x); \
105 _X = OSSwapHostToLittleInt32(_x); \
108 _X = OSSwapHostToLittleInt16(_x); \
114 __OSBogusByteSwap__(); \
121 #define big2wire(x) \
122 ({ typeof (x) _X, _x = (x); \
123 switch (sizeof(_x)) { \
125 _X = OSSwapLittleToHostInt64(_x); \
128 _X = OSSwapLittleToHostInt32(_x); \
131 _X = OSSwapLittleToHostInt16(_x); \
137 __OSBogusByteSwap__(); \
143 union _launch_double_u
{
148 #define host2wire_f(x) ({ \
149 typeof(x) _F, _f = (x); \
150 union _launch_double_u s; \
152 s.iv = host2wire(s.iv); \
157 #define big2wire_f(x) ({ \
158 typeof(x) _F, _f = (x); \
159 union _launch_double_u s; \
161 s.iv = big2wire(s.iv); \
167 struct launch_msg_header
{
172 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
175 LAUNCHD_USE_CHECKIN_FD
,
176 LAUNCHD_USE_OTHER_FD
,
192 static launch_data_t
launch_data_array_pop_first(launch_data_t where
);
193 static int _fd(int fd
);
194 static void launch_client_init(void);
195 static void launch_msg_getmsgs(launch_data_t m
, void *context
);
196 static launch_data_t
launch_msg_internal(launch_data_t d
);
197 static void launch_mach_checkin_service(launch_data_t obj
, const char *key
, void *context
);
200 _launch_init_globals(launch_globals_t globals
)
202 pthread_once_t once
= PTHREAD_ONCE_INIT
;
203 globals
->lc_once
= once
;
204 pthread_mutex_init(&globals
->lc_mtx
, NULL
);
207 #if !_LIBLAUNCH_HAS_ALLOC_ONCE
208 launch_globals_t __launch_globals
;
211 _launch_globals_init(void)
213 __launch_globals
= calloc(1, sizeof(struct launch_globals_s
));
214 _launch_init_globals(__launch_globals
);
218 _launch_globals_impl(void)
220 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
221 pthread_once(&once
, &_launch_globals_init
);
222 return __launch_globals
;
227 launch_client_init(void)
229 struct sockaddr_un sun
;
230 char *where
= getenv(LAUNCHD_SOCKET_ENV
);
231 char *_launchd_fd
= getenv(LAUNCHD_TRUSTED_FD_ENV
);
232 int dfd
, lfd
= -1, cifd
= -1;
236 cifd
= strtol(_launchd_fd
, NULL
, 10);
237 if ((dfd
= dup(cifd
)) >= 0) {
243 unsetenv(LAUNCHD_TRUSTED_FD_ENV
);
246 memset(&sun
, 0, sizeof(sun
));
247 sun
.sun_family
= AF_UNIX
;
249 /* The rules are as follows.
250 * - All users (including root) talk to their per-user launchd's by default.
251 * - If we have been invoked under sudo, talk to the system launchd.
252 * - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then
253 * talk to the system launchd.
255 if (where
&& where
[0] != '\0') {
256 strncpy(sun
.sun_path
, where
, sizeof(sun
.sun_path
));
258 if (_vprocmgr_getsocket(spath
) == 0) {
259 if ((getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0) {
260 /* Talk to the system launchd. */
261 strncpy(sun
.sun_path
, LAUNCHD_SOCK_PREFIX
"/sock", sizeof(sun
.sun_path
));
263 /* Talk to our per-user launchd. */
266 min_len
= sizeof(sun
.sun_path
) < sizeof(spath
) ? sizeof(sun
.sun_path
) : sizeof(spath
);
268 strncpy(sun
.sun_path
, spath
, min_len
);
273 launch_globals_t globals
= _launch_globals();
274 if ((lfd
= _fd(socket(AF_UNIX
, SOCK_STREAM
, 0))) == -1) {
278 #if TARGET_OS_EMBEDDED
279 (void)vproc_swap_integer(NULL
, VPROC_GSK_EMBEDDEDROOTEQUIVALENT
, NULL
, &globals
->s_am_embedded_god
);
281 if (-1 == connect(lfd
, (struct sockaddr
*)&sun
, sizeof(sun
))) {
282 if (cifd
!= -1 || globals
->s_am_embedded_god
) {
283 /* There is NO security enforced by this check. This is just a hint to our
284 * library that we shouldn't error out due to failing to open this socket. If
285 * we inherited a trusted file descriptor, we shouldn't fail. This should be
286 * adequate for clients' expectations.
295 if (!(globals
->l
= launchd_fdopen(lfd
, cifd
))) {
299 if (!(globals
->async_resp
= launch_data_alloc(LAUNCH_DATA_ARRAY
))) {
306 launchd_close(globals
->l
, close
);
308 } else if (lfd
!= -1) {
317 launch_data_alloc(launch_data_type_t t
)
319 launch_data_t d
= calloc(1, sizeof(struct _launch_data
));
324 case LAUNCH_DATA_DICTIONARY
:
325 case LAUNCH_DATA_ARRAY
:
326 d
->_array
= malloc(0);
328 case LAUNCH_DATA_OPAQUE
:
329 d
->opaque
= malloc(0);
339 launch_data_get_type(launch_data_t d
)
345 launch_data_free(launch_data_t d
)
350 case LAUNCH_DATA_DICTIONARY
:
351 case LAUNCH_DATA_ARRAY
:
352 for (i
= 0; i
< d
->_array_cnt
; i
++) {
354 launch_data_free(d
->_array
[i
]);
359 case LAUNCH_DATA_STRING
:
363 case LAUNCH_DATA_OPAQUE
:
374 launch_data_dict_get_count(launch_data_t dict
)
376 return dict
->_array_cnt
/ 2;
380 launch_data_dict_insert(launch_data_t dict
, launch_data_t what
, const char *key
)
383 launch_data_t thekey
= launch_data_alloc(LAUNCH_DATA_STRING
);
385 launch_data_set_string(thekey
, key
);
387 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
388 if (!strcasecmp(key
, dict
->_array
[i
]->string
)) {
389 launch_data_array_set_index(dict
, thekey
, i
);
390 launch_data_array_set_index(dict
, what
, i
+ 1);
394 launch_data_array_set_index(dict
, thekey
, i
);
395 launch_data_array_set_index(dict
, what
, i
+ 1);
400 launch_data_dict_lookup(launch_data_t dict
, const char *key
)
404 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
407 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
408 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
409 return dict
->_array
[i
+ 1];
416 launch_data_dict_remove(launch_data_t dict
, const char *key
)
420 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
421 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
424 if (i
== dict
->_array_cnt
)
426 launch_data_free(dict
->_array
[i
]);
427 launch_data_free(dict
->_array
[i
+ 1]);
428 memmove(dict
->_array
+ i
, dict
->_array
+ i
+ 2, (dict
->_array_cnt
- (i
+ 2)) * sizeof(launch_data_t
));
429 dict
->_array_cnt
-= 2;
434 launch_data_dict_iterate(launch_data_t dict
, void (*cb
)(launch_data_t
, const char *, void *), void *context
)
438 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
) {
442 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
443 cb(dict
->_array
[i
+ 1], dict
->_array
[i
]->string
, context
);
448 launch_data_array_set_index(launch_data_t where
, launch_data_t what
, size_t ind
)
450 if ((ind
+ 1) >= where
->_array_cnt
) {
451 where
->_array
= reallocf(where
->_array
, (ind
+ 1) * sizeof(launch_data_t
));
452 memset(where
->_array
+ where
->_array_cnt
, 0, (ind
+ 1 - where
->_array_cnt
) * sizeof(launch_data_t
));
453 where
->_array_cnt
= ind
+ 1;
456 if (where
->_array
[ind
]) {
457 launch_data_free(where
->_array
[ind
]);
460 where
->_array
[ind
] = what
;
465 launch_data_array_get_index(launch_data_t where
, size_t ind
)
467 if (LAUNCH_DATA_ARRAY
!= where
->type
|| ind
>= where
->_array_cnt
) {
470 return where
->_array
[ind
];
475 launch_data_array_pop_first(launch_data_t where
)
477 launch_data_t r
= NULL
;
479 if (where
->_array_cnt
> 0) {
480 r
= where
->_array
[0];
481 memmove(where
->_array
, where
->_array
+ 1, (where
->_array_cnt
- 1) * sizeof(launch_data_t
));
488 launch_data_array_get_count(launch_data_t where
)
490 if (LAUNCH_DATA_ARRAY
!= where
->type
)
492 return where
->_array_cnt
;
496 launch_data_set_errno(launch_data_t d
, int e
)
503 launch_data_set_fd(launch_data_t d
, int fd
)
510 launch_data_set_machport(launch_data_t d
, mach_port_t p
)
517 launch_data_set_integer(launch_data_t d
, long long n
)
524 launch_data_set_bool(launch_data_t d
, bool b
)
531 launch_data_set_real(launch_data_t d
, double n
)
538 launch_data_set_string(launch_data_t d
, const char *s
)
542 d
->string
= strdup(s
);
544 d
->string_len
= strlen(d
->string
);
551 launch_data_set_opaque(launch_data_t d
, const void *o
, size_t os
)
556 d
->opaque
= malloc(os
);
558 memcpy(d
->opaque
, o
, os
);
565 launch_data_get_errno(launch_data_t d
)
571 launch_data_get_fd(launch_data_t d
)
577 launch_data_get_machport(launch_data_t d
)
583 launch_data_get_integer(launch_data_t d
)
589 launch_data_get_bool(launch_data_t d
)
595 launch_data_get_real(launch_data_t d
)
601 launch_data_get_string(launch_data_t d
)
603 if (LAUNCH_DATA_STRING
!= d
->type
)
609 launch_data_get_opaque(launch_data_t d
)
611 if (LAUNCH_DATA_OPAQUE
!= d
->type
)
617 launch_data_get_opaque_size(launch_data_t d
)
619 return d
->opaque_size
;
623 launchd_getfd(launch_t l
)
625 return (l
->which
== LAUNCHD_USE_CHECKIN_FD
) ? l
->cifd
: l
->fd
;
629 launchd_fdopen(int fd
, int cifd
)
633 c
= calloc(1, sizeof(struct _launch
));
640 if (c
->fd
== -1 || (c
->fd
!= -1 && c
->cifd
!= -1)) {
641 c
->which
= LAUNCHD_USE_CHECKIN_FD
;
642 } else if (c
->cifd
== -1) {
643 c
->which
= LAUNCHD_USE_OTHER_FD
;
646 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
647 fcntl(cifd
, F_SETFL
, O_NONBLOCK
);
649 if ((c
->sendbuf
= malloc(0)) == NULL
)
651 if ((c
->sendfds
= malloc(0)) == NULL
)
653 if ((c
->recvbuf
= malloc(0)) == NULL
)
655 if ((c
->recvfds
= malloc(0)) == NULL
)
674 launchd_close(launch_t lh
, typeof(close
) closefunc
)
676 launch_globals_t globals
= _launch_globals();
678 if (globals
->in_flight_msg_recv_client
== lh
) {
679 globals
->in_flight_msg_recv_client
= NULL
;
695 #define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
698 launch_data_pack(launch_data_t d
, void *where
, size_t len
, int *fd_where
, size_t *fd_cnt
)
700 launch_data_t o_in_w
= where
;
701 size_t i
, rsz
, node_data_len
= sizeof(struct _launch_data
);
703 if (node_data_len
> len
) {
707 where
+= node_data_len
;
709 o_in_w
->type
= host2wire(d
->type
);
713 case LAUNCH_DATA_INTEGER
:
714 o_in_w
->number
= host2wire(d
->number
);
716 case LAUNCH_DATA_REAL
:
717 o_in_w
->float_num
= host2wire_f(d
->float_num
);
719 case LAUNCH_DATA_BOOL
:
720 o_in_w
->boolean
= host2wire(d
->boolean
);
722 case LAUNCH_DATA_ERRNO
:
723 o_in_w
->err
= host2wire(d
->err
);
726 o_in_w
->fd
= host2wire(d
->fd
);
727 if (fd_where
&& d
->fd
!= -1) {
728 fd_where
[*fd_cnt
] = d
->fd
;
732 case LAUNCH_DATA_STRING
:
733 o_in_w
->string_len
= host2wire(d
->string_len
);
734 node_data_len
+= ROUND_TO_64BIT_WORD_SIZE(d
->string_len
+ 1);
736 if (node_data_len
> len
) {
739 memcpy(where
, d
->string
, d
->string_len
+ 1);
741 /* Zero padded data. */
742 pad_len
= ROUND_TO_64BIT_WORD_SIZE(d
->string_len
+ 1) - (d
->string_len
+ 1);
743 bzero(where
+ d
->string_len
+ 1, pad_len
);
746 case LAUNCH_DATA_OPAQUE
:
747 o_in_w
->opaque_size
= host2wire(d
->opaque_size
);
748 node_data_len
+= ROUND_TO_64BIT_WORD_SIZE(d
->opaque_size
);
749 if (node_data_len
> len
) {
752 memcpy(where
, d
->opaque
, d
->opaque_size
);
754 /* Zero padded data. */
755 pad_len
= ROUND_TO_64BIT_WORD_SIZE(d
->opaque_size
) - d
->opaque_size
;
756 bzero(where
+ d
->opaque_size
, pad_len
);
759 case LAUNCH_DATA_DICTIONARY
:
760 case LAUNCH_DATA_ARRAY
:
761 o_in_w
->_array_cnt
= host2wire(d
->_array_cnt
);
762 node_data_len
+= d
->_array_cnt
* sizeof(uint64_t);
763 if (node_data_len
> len
) {
767 where
+= d
->_array_cnt
* sizeof(uint64_t);
769 for (i
= 0; i
< d
->_array_cnt
; i
++) {
770 rsz
= launch_data_pack(d
->_array
[i
], where
, len
- node_data_len
, fd_where
, fd_cnt
);
775 node_data_len
+= rsz
;
782 return node_data_len
;
786 launch_data_unpack(void *data
, size_t data_size
, int *fds
, size_t fd_cnt
, size_t *data_offset
, size_t *fdoffset
)
788 launch_data_t r
= data
+ *data_offset
;
791 //Check for integer underflow
792 if (data_size
< *data_offset
)
795 if ((data_size
- *data_offset
) < sizeof(struct _launch_data
))
797 *data_offset
+= sizeof(struct _launch_data
);
799 switch (big2wire(r
->type
)) {
800 case LAUNCH_DATA_DICTIONARY
:
801 case LAUNCH_DATA_ARRAY
:
802 tmpcnt
= big2wire(r
->_array_cnt
);
804 //Check for integer overflows
805 if (tmpcnt
> SIZE_MAX
/ sizeof(uint64_t)) {
810 if ((data_size
- *data_offset
) < (tmpcnt
* sizeof(uint64_t))) {
814 r
->_array
= data
+ *data_offset
;
815 *data_offset
+= tmpcnt
* sizeof(uint64_t);
816 for (i
= 0; i
< tmpcnt
; i
++) {
817 r
->_array
[i
] = launch_data_unpack(data
, data_size
, fds
, fd_cnt
, data_offset
, fdoffset
);
818 if (r
->_array
[i
] == NULL
)
821 r
->_array_cnt
= tmpcnt
;
823 case LAUNCH_DATA_STRING
:
824 tmpcnt
= big2wire(r
->string_len
);
825 if ((data_size
- *data_offset
) < (tmpcnt
+ 1)) {
829 r
->string
= data
+ *data_offset
;
830 r
->string_len
= tmpcnt
;
831 *data_offset
+= ROUND_TO_64BIT_WORD_SIZE(tmpcnt
+ 1);
833 case LAUNCH_DATA_OPAQUE
:
834 tmpcnt
= big2wire(r
->opaque_size
);
835 if ((data_size
- *data_offset
) < tmpcnt
) {
839 r
->opaque
= data
+ *data_offset
;
840 r
->opaque_size
= tmpcnt
;
841 *data_offset
+= ROUND_TO_64BIT_WORD_SIZE(tmpcnt
);
844 if (r
->fd
!= -1 && fd_cnt
> *fdoffset
) {
845 r
->fd
= _fd(fds
[*fdoffset
]);
849 case LAUNCH_DATA_INTEGER
:
850 r
->number
= big2wire(r
->number
);
852 case LAUNCH_DATA_REAL
:
853 r
->float_num
= big2wire_f(r
->float_num
);
855 case LAUNCH_DATA_BOOL
:
856 r
->boolean
= big2wire(r
->boolean
);
858 case LAUNCH_DATA_ERRNO
:
859 r
->err
= big2wire(r
->err
);
860 case LAUNCH_DATA_MACHPORT
:
868 r
->type
= big2wire(r
->type
);
874 launchd_msg_send(launch_t lh
, launch_data_t d
)
876 struct launch_msg_header lmh
;
877 struct cmsghdr
*cm
= NULL
;
880 size_t sentctrllen
= 0;
883 int fd2use
= launchd_getfd(lh
);
889 memset(&mh
, 0, sizeof(mh
));
891 /* confirm that the next hack works */
892 assert((d
&& lh
->sendlen
== 0) || (!d
&& lh
->sendlen
));
895 size_t fd_slots_used
= 0;
896 size_t good_enough_size
= 10 * 1024 * 1024;
899 /* hack, see the above assert to verify "correctness" */
901 lh
->sendbuf
= malloc(good_enough_size
);
908 lh
->sendfds
= malloc(4 * 1024);
916 lh
->sendlen
= launch_data_pack(d
, lh
->sendbuf
, good_enough_size
, lh
->sendfds
, &fd_slots_used
);
918 if (lh
->sendlen
== 0) {
923 lh
->sendfdcnt
= fd_slots_used
;
925 msglen
= lh
->sendlen
+ sizeof(struct launch_msg_header
); /* type promotion to make the host2wire() macro work right */
926 lmh
.len
= host2wire(msglen
);
927 lmh
.magic
= host2wire(LAUNCH_MSG_HEADER_MAGIC
);
929 iov
[0].iov_base
= &lmh
;
930 iov
[0].iov_len
= sizeof(lmh
);
934 mh
.msg_iov
= iov
+ 1;
938 iov
[1].iov_base
= lh
->sendbuf
;
939 iov
[1].iov_len
= lh
->sendlen
;
942 if (lh
->sendfdcnt
> 0) {
943 sentctrllen
= mh
.msg_controllen
= CMSG_SPACE(lh
->sendfdcnt
* sizeof(int));
944 cm
= alloca(mh
.msg_controllen
);
947 memset(cm
, 0, mh
.msg_controllen
);
949 cm
->cmsg_len
= CMSG_LEN(lh
->sendfdcnt
* sizeof(int));
950 cm
->cmsg_level
= SOL_SOCKET
;
951 cm
->cmsg_type
= SCM_RIGHTS
;
953 memcpy(CMSG_DATA(cm
), lh
->sendfds
, lh
->sendfdcnt
* sizeof(int));
956 if ((r
= sendmsg(fd2use
, &mh
, 0)) == -1) {
961 } else if (sentctrllen
!= mh
.msg_controllen
) {
967 r
-= sizeof(struct launch_msg_header
);
971 if (lh
->sendlen
> 0) {
972 memmove(lh
->sendbuf
, lh
->sendbuf
+ r
, lh
->sendlen
);
975 lh
->sendbuf
= malloc(0);
980 lh
->sendfds
= malloc(0);
982 if (lh
->sendlen
> 0) {
993 launch_globals_t globals
= _launch_globals();
994 pthread_once(&globals
->lc_once
, launch_client_init
);
1001 return globals
->l
->fd
;
1005 launch_msg_getmsgs(launch_data_t m
, void *context
)
1007 launch_data_t async_resp
, *sync_resp
= context
;
1009 launch_globals_t globals
= _launch_globals();
1011 if ((LAUNCH_DATA_DICTIONARY
== launch_data_get_type(m
)) && (async_resp
= launch_data_dict_lookup(m
, LAUNCHD_ASYNC_MSG_KEY
))) {
1012 launch_data_array_set_index(globals
->async_resp
, launch_data_copy(async_resp
), launch_data_array_get_count(globals
->async_resp
));
1014 *sync_resp
= launch_data_copy(m
);
1019 launch_mach_checkin_service(launch_data_t obj
, const char *key
, void *context
__attribute__((unused
)))
1021 kern_return_t result
;
1025 strlcpy(srvnm
, key
, sizeof(srvnm
));
1027 result
= bootstrap_check_in(bootstrap_port
, srvnm
, &p
);
1029 if (result
== BOOTSTRAP_SUCCESS
)
1030 launch_data_set_machport(obj
, p
);
1034 launch_msg(launch_data_t d
)
1036 launch_data_t mps
, r
= launch_msg_internal(d
);
1038 if (launch_data_get_type(d
) == LAUNCH_DATA_STRING
) {
1039 if (strcmp(launch_data_get_string(d
), LAUNCH_KEY_CHECKIN
) != 0)
1043 if (launch_data_get_type(r
) != LAUNCH_DATA_DICTIONARY
)
1045 mps
= launch_data_dict_lookup(r
, LAUNCH_JOBKEY_MACHSERVICES
);
1048 launch_data_dict_iterate(mps
, launch_mach_checkin_service
, NULL
);
1054 extern kern_return_t
vproc_mig_set_security_session(mach_port_t
, uuid_t
, mach_port_t
);
1057 uuid_data_is_null(launch_data_t d
)
1059 bool result
= false;
1060 if (launch_data_get_type(d
) == LAUNCH_DATA_OPAQUE
&& launch_data_get_opaque_size(d
) == sizeof(uuid_t
)) {
1061 uuid_t existing_uuid
;
1062 memcpy(existing_uuid
, launch_data_get_opaque(d
), sizeof(uuid_t
));
1064 /* A NULL UUID tells us to keep the session inherited from the parent. */
1065 result
= (bool)uuid_is_null(existing_uuid
);
1072 launch_msg_internal(launch_data_t d
)
1074 launch_data_t resp
= NULL
;
1076 if (d
&& (launch_data_get_type(d
) == LAUNCH_DATA_STRING
)
1077 && (strcmp(launch_data_get_string(d
), LAUNCH_KEY_GETJOBS
) == 0)
1078 && vproc_swap_complex(NULL
, VPROC_GSK_ALLJOBS
, NULL
, &resp
) == NULL
) {
1082 launch_globals_t globals
= _launch_globals();
1083 pthread_once(&globals
->lc_once
, launch_client_init
);
1090 if ((launch_data_get_type(d
) == LAUNCH_DATA_STRING
&& strcmp(launch_data_get_string(d
), LAUNCH_KEY_CHECKIN
) == 0) || globals
->s_am_embedded_god
) {
1091 globals
->l
->which
= LAUNCHD_USE_CHECKIN_FD
;
1093 globals
->l
->which
= LAUNCHD_USE_OTHER_FD
;
1096 fd2use
= launchd_getfd(globals
->l
);
1103 #if !TARGET_OS_EMBEDDED
1105 launch_data_t uuid_d
= NULL
;
1106 size_t jobs_that_need_sessions
= 0;
1107 if (d
&& launch_data_get_type(d
) == LAUNCH_DATA_DICTIONARY
) {
1108 launch_data_t v
= launch_data_dict_lookup(d
, LAUNCH_KEY_SUBMITJOB
);
1110 if (v
&& launch_data_get_type(v
) == LAUNCH_DATA_ARRAY
) {
1111 size_t cnt
= launch_data_array_get_count(v
);
1114 uuid_generate(uuid
);
1115 for (i
= 0; i
< cnt
; i
++) {
1116 launch_data_t ji
= launch_data_array_get_index(v
, i
);
1117 if (launch_data_get_type(ji
) == LAUNCH_DATA_DICTIONARY
) {
1118 launch_data_t existing_v
= launch_data_dict_lookup(ji
, LAUNCH_JOBKEY_SECURITYSESSIONUUID
);
1120 /* I really wish these were reference-counted. Sigh... */
1121 uuid_d
= launch_data_new_opaque(uuid
, sizeof(uuid
));
1122 launch_data_dict_insert(ji
, uuid_d
, LAUNCH_JOBKEY_SECURITYSESSIONUUID
);
1123 jobs_that_need_sessions
++;
1124 } else if (launch_data_get_type(existing_v
) == LAUNCH_DATA_OPAQUE
) {
1125 jobs_that_need_sessions
+= uuid_data_is_null(existing_v
) ? 0 : 1;
1129 } else if (v
&& launch_data_get_type(v
) == LAUNCH_DATA_DICTIONARY
) {
1130 launch_data_t existing_v
= launch_data_dict_lookup(v
, LAUNCH_JOBKEY_SECURITYSESSIONUUID
);
1132 uuid_generate(uuid
);
1133 uuid_d
= launch_data_new_opaque(uuid
, sizeof(uuid
));
1134 launch_data_dict_insert(v
, uuid_d
, LAUNCH_JOBKEY_SECURITYSESSIONUUID
);
1135 jobs_that_need_sessions
++;
1137 jobs_that_need_sessions
+= uuid_data_is_null(existing_v
) ? 0 : 1;
1143 pthread_mutex_lock(&globals
->lc_mtx
);
1145 if (d
&& launchd_msg_send(globals
->l
, d
) == -1) {
1147 if (errno
!= EAGAIN
)
1149 } while (launchd_msg_send(globals
->l
, NULL
) == -1);
1152 while (resp
== NULL
) {
1153 if (d
== NULL
&& launch_data_array_get_count(globals
->async_resp
) > 0) {
1154 resp
= launch_data_array_pop_first(globals
->async_resp
);
1157 if (launchd_msg_recv(globals
->l
, launch_msg_getmsgs
, &resp
) == -1) {
1158 if (errno
!= EAGAIN
) {
1160 } else if (d
== NULL
) {
1167 FD_SET(fd2use
, &rfds
);
1169 select(fd2use
+ 1, &rfds
, NULL
, NULL
, NULL
);
1175 #if !TARGET_OS_EMBEDDED
1176 if (!uuid_is_null(uuid
) && resp
&& jobs_that_need_sessions
> 0) {
1177 mach_port_t session_port
= _audit_session_self();
1178 launch_data_type_t resp_type
= launch_data_get_type(resp
);
1180 bool set_session
= false;
1181 if (resp_type
== LAUNCH_DATA_ERRNO
) {
1182 set_session
= (launch_data_get_errno(resp
) == ENEEDAUTH
);
1183 } else if (resp_type
== LAUNCH_DATA_ARRAY
) {
1187 kern_return_t kr
= KERN_FAILURE
;
1189 kr
= vproc_mig_set_security_session(bootstrap_port
, uuid
, session_port
);
1192 if (kr
== KERN_SUCCESS
) {
1193 if (resp_type
== LAUNCH_DATA_ERRNO
) {
1194 launch_data_set_errno(resp
, 0);
1197 for (i
= 0; i
< launch_data_array_get_count(resp
); i
++) {
1198 launch_data_t ri
= launch_data_array_get_index(resp
, i
);
1201 if (launch_data_get_type(ri
) == LAUNCH_DATA_ERRNO
&& (recvd_err
= launch_data_get_errno(ri
))) {
1202 launch_data_set_errno(ri
, recvd_err
== ENEEDAUTH
? 0 : recvd_err
);
1208 mach_port_deallocate(mach_task_self(), session_port
);
1212 pthread_mutex_unlock(&globals
->lc_mtx
);
1218 launchd_msg_recv(launch_t lh
, void (*cb
)(launch_data_t
, void *), void *context
)
1220 struct cmsghdr
*cm
= alloca(4096);
1221 launch_data_t rmsg
= NULL
;
1222 size_t data_offset
, fd_offset
;
1227 int fd2use
= launchd_getfd(lh
);
1233 memset(&mh
, 0, sizeof(mh
));
1237 lh
->recvbuf
= reallocf(lh
->recvbuf
, lh
->recvlen
+ 8*1024);
1239 iov
.iov_base
= lh
->recvbuf
+ lh
->recvlen
;
1240 iov
.iov_len
= 8*1024;
1241 mh
.msg_control
= cm
;
1242 mh
.msg_controllen
= 4096;
1244 if ((r
= recvmsg(fd2use
, &mh
, 0)) == -1)
1250 if (mh
.msg_flags
& MSG_CTRUNC
) {
1251 errno
= ECONNABORTED
;
1255 if (mh
.msg_controllen
> 0) {
1256 lh
->recvfds
= reallocf(lh
->recvfds
, lh
->recvfdcnt
* sizeof(int) + mh
.msg_controllen
- sizeof(struct cmsghdr
));
1257 memcpy(lh
->recvfds
+ lh
->recvfdcnt
, CMSG_DATA(cm
), mh
.msg_controllen
- sizeof(struct cmsghdr
));
1258 lh
->recvfdcnt
+= (mh
.msg_controllen
- sizeof(struct cmsghdr
)) / sizeof(int);
1263 while (lh
->recvlen
> 0) {
1264 struct launch_msg_header
*lmhp
= lh
->recvbuf
;
1266 data_offset
= sizeof(struct launch_msg_header
);
1269 if (lh
->recvlen
< sizeof(struct launch_msg_header
))
1270 goto need_more_data
;
1272 tmplen
= big2wire(lmhp
->len
);
1274 if (big2wire(lmhp
->magic
) != LAUNCH_MSG_HEADER_MAGIC
|| tmplen
<= sizeof(struct launch_msg_header
)) {
1279 if (lh
->recvlen
< tmplen
) {
1280 goto need_more_data
;
1283 if ((rmsg
= launch_data_unpack(lh
->recvbuf
, lh
->recvlen
, lh
->recvfds
, lh
->recvfdcnt
, &data_offset
, &fd_offset
)) == NULL
) {
1288 launch_globals_t globals
= _launch_globals();
1290 globals
->in_flight_msg_recv_client
= lh
;
1294 /* launchd and only launchd can call launchd_close() as a part of the callback */
1295 if (globals
->in_flight_msg_recv_client
== NULL
) {
1300 lh
->recvlen
-= data_offset
;
1301 if (lh
->recvlen
> 0) {
1302 memmove(lh
->recvbuf
, lh
->recvbuf
+ data_offset
, lh
->recvlen
);
1305 lh
->recvbuf
= malloc(0);
1308 lh
->recvfdcnt
-= fd_offset
;
1309 if (lh
->recvfdcnt
> 0) {
1310 memmove(lh
->recvfds
, lh
->recvfds
+ fd_offset
, lh
->recvfdcnt
* sizeof(int));
1313 lh
->recvfds
= malloc(0);
1326 launch_data_copy(launch_data_t o
)
1328 launch_data_t r
= launch_data_alloc(o
->type
);
1332 memcpy(r
, o
, sizeof(struct _launch_data
));
1335 case LAUNCH_DATA_DICTIONARY
:
1336 case LAUNCH_DATA_ARRAY
:
1337 r
->_array
= calloc(1, o
->_array_cnt
* sizeof(launch_data_t
));
1338 for (i
= 0; i
< o
->_array_cnt
; i
++) {
1340 r
->_array
[i
] = launch_data_copy(o
->_array
[i
]);
1343 case LAUNCH_DATA_STRING
:
1344 r
->string
= strdup(o
->string
);
1346 case LAUNCH_DATA_OPAQUE
:
1347 r
->opaque
= malloc(o
->opaque_size
);
1348 memcpy(r
->opaque
, o
->opaque
, o
->opaque_size
);
1361 fcntl(fd
, F_SETFD
, 1);
1366 launch_data_new_errno(int e
)
1368 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_ERRNO
);
1371 launch_data_set_errno(r
, e
);
1377 launch_data_new_fd(int fd
)
1379 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_FD
);
1382 launch_data_set_fd(r
, fd
);
1388 launch_data_new_machport(mach_port_t p
)
1390 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_MACHPORT
);
1393 launch_data_set_machport(r
, p
);
1399 launch_data_new_integer(long long n
)
1401 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
1404 launch_data_set_integer(r
, n
);
1410 launch_data_new_bool(bool b
)
1412 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
1415 launch_data_set_bool(r
, b
);
1421 launch_data_new_real(double d
)
1423 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_REAL
);
1426 launch_data_set_real(r
, d
);
1432 launch_data_new_string(const char *s
)
1434 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_STRING
);
1439 if (!launch_data_set_string(r
, s
)) {
1440 launch_data_free(r
);
1448 launch_data_new_opaque(const void *o
, size_t os
)
1450 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_OPAQUE
);
1455 if (!launch_data_set_opaque(r
, o
, os
)) {
1456 launch_data_free(r
);
1464 load_launchd_jobs_at_loginwindow_prompt(int flags
__attribute__((unused
)), ...)
1466 _vprocmgr_init(VPROCMGR_SESSION_LOGINWINDOW
);
1470 create_and_switch_to_per_session_launchd(const char *login
__attribute__((unused
)), int flags
, ...)
1472 uid_t target_user
= geteuid() ? geteuid() : getuid();
1473 if (_vprocmgr_move_subset_to_user(target_user
, VPROCMGR_SESSION_AQUA
, flags
)) {