Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/openlaunchd
Path: blob/master/liblaunch/liblaunch.c
374 views
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
26
#ifdef __APPLE__
27
/* NOTE: ktrace.h appears to enable Apple OS specific kernel tracing. Until
28
* this functionality can be verified further, there's no sense pulling it into
29
* the non-Apple builds
30
*/
31
#include "ktrace.h"
32
#endif
33
34
#if HAS_MACH
35
#include <mach/mach.h>
36
#endif
37
#include <time.h>
38
#include <sys/types.h>
39
#include <sys/socket.h>
40
#include <sys/fcntl.h>
41
#include <sys/un.h>
42
#include <sys/uio.h>
43
#include <sys/stat.h>
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <pthread.h>
48
#include <unistd.h>
49
#include <errno.h>
50
#include <pwd.h>
51
#include <assert.h>
52
#include <uuid/uuid.h>
53
#include <sys/syscall.h>
54
#include <dlfcn.h>
55
56
#include "byteswap.h"
57
58
#ifdef __LP64__
59
/* workaround: 5723161 */
60
#ifndef __DARWIN_ALIGN32
61
#define __DARWIN_ALIGN32(x) (((size_t)(x) + 3) & ~3)
62
#endif
63
#undef CMSG_DATA
64
#define CMSG_DATA(cmsg) \
65
((uint8_t *)(cmsg) + __DARWIN_ALIGN32(sizeof(struct cmsghdr)))
66
#undef CMSG_SPACE
67
#define CMSG_SPACE(l) \
68
(__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + __DARWIN_ALIGN32(l))
69
#undef CMSG_LEN
70
#define CMSG_LEN(l) \
71
(__DARWIN_ALIGN32(sizeof(struct cmsghdr)) + (l))
72
#endif
73
74
75
#ifdef __APPLE__
76
#include "bootstrap.h"
77
#include "vproc.h"
78
#include "vproc_priv.h"
79
#include "vproc_internal.h"
80
#endif
81
82
83
struct launch_msg_header {
84
uint64_t magic;
85
uint64_t len;
86
};
87
88
#define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
89
90
/* launch_data_array_pop_first is located in launch_data.c */
91
launch_data_t launch_data_array_pop_first(launch_data_t where);
92
/* _fd is used in both liblaunch.c and inside of launch_data.c */
93
int _fd(int fd);
94
void launch_client_init(void);
95
void launch_msg_getmsgs(launch_data_t m, void *context);
96
launch_data_t launch_msg_internal(launch_data_t d);
97
#if HAS_MACH
98
static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
99
#endif
100
101
void
102
_launch_init_globals(launch_globals_t globals)
103
{
104
pthread_once_t once = PTHREAD_ONCE_INIT;
105
globals->lc_once = once;
106
/* XXX: Not checking return value of pthread_mutex_init */
107
pthread_mutex_init(&globals->lc_mtx, NULL);
108
}
109
110
#if !_LIBLAUNCH_HAS_ALLOC_ONCE
111
launch_globals_t __launch_globals;
112
113
void
114
_launch_globals_init(void)
115
{
116
__launch_globals = calloc(1, sizeof(struct launch_globals_s));
117
_launch_init_globals(__launch_globals);
118
}
119
120
launch_globals_t
121
_launch_globals_impl(void)
122
{
123
static pthread_once_t once = PTHREAD_ONCE_INIT;
124
pthread_once(&once, &_launch_globals_init);
125
return __launch_globals;
126
}
127
#endif
128
129
/* Set the file descriptor to FD_CLOEXEC, in effect, the descriptor will close
130
* if execve(2) is called (we transform into a new process)
131
*/
132
int _fd(int fd)
133
{
134
assert(0 <= fd);
135
136
if (fd >= 0) {
137
fcntl(fd, F_SETFD, FD_CLOEXEC);
138
}
139
return fd;
140
}
141
142
#ifndef UNIT_TEST
143
void
144
launch_client_init(void)
145
{
146
struct sockaddr_un sun;
147
char *where = getenv(LAUNCHD_SOCKET_ENV);
148
char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
149
int dfd, lfd = -1, cifd = -1;
150
#ifdef __APPLE__
151
name_t spath;
152
#else
153
#pragma message "PORT: Figure out how to handle spath from bootstrap"
154
#endif
155
156
if (_launchd_fd) {
157
cifd = strtol(_launchd_fd, NULL, 10);
158
if ((dfd = dup(cifd)) >= 0) {
159
close(dfd);
160
_fd(cifd);
161
} else {
162
cifd = -1;
163
}
164
unsetenv(LAUNCHD_TRUSTED_FD_ENV);
165
}
166
167
memset(&sun, 0, sizeof(sun));
168
sun.sun_family = AF_UNIX;
169
170
/* The rules are as follows.
171
* - All users (including root) talk to their per-user launchd's by default.
172
* - If we have been invoked under sudo, talk to the system launchd.
173
* - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then
174
* talk to the system launchd.
175
*/
176
if (where && where[0] != '\0') {
177
strncpy(sun.sun_path, where, sizeof(sun.sun_path));
178
} else {
179
#ifdef __APPLE__
180
if (_vprocmgr_getsocket(spath) == 0) {
181
if ((getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0) {
182
/* Talk to the system launchd. */
183
strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
184
} else {
185
/* Talk to our per-user launchd. */
186
size_t min_len;
187
188
min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath);
189
190
strncpy(sun.sun_path, spath, min_len);
191
}
192
}
193
#else
194
fprintf(stderr, "Reaching dead branch for this platform in liblaunch.c\n");
195
abort();
196
#endif
197
}
198
199
launch_globals_t globals = _launch_globals();
200
if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) {
201
goto out_bad;
202
}
203
204
#if TARGET_OS_EMBEDDED
205
(void)vproc_swap_integer(NULL, VPROC_GSK_EMBEDDEDROOTEQUIVALENT, NULL, &globals->s_am_embedded_god);
206
#endif
207
if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) {
208
if (cifd != -1 || globals->s_am_embedded_god) {
209
/* There is NO security enforced by this check. This is just a hint to our
210
* library that we shouldn't error out due to failing to open this socket. If
211
* we inherited a trusted file descriptor, we shouldn't fail. This should be
212
* adequate for clients' expectations.
213
*/
214
close(lfd);
215
lfd = -1;
216
} else {
217
goto out_bad;
218
}
219
}
220
221
if (!(globals->l = launchd_fdopen(lfd, cifd))) {
222
goto out_bad;
223
}
224
225
if (!(globals->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
226
goto out_bad;
227
}
228
229
return;
230
out_bad:
231
if (globals->l) {
232
launchd_close(globals->l, close);
233
globals->l = NULL;
234
} else if (lfd != -1) {
235
close(lfd);
236
}
237
if (cifd != -1) {
238
close(cifd);
239
}
240
}
241
242
launch_t
243
launchd_fdopen(int fd, int cifd)
244
{
245
launch_t c;
246
247
c = calloc(1, sizeof(struct _launch));
248
if (!c)
249
return NULL;
250
251
c->fd = fd;
252
c->cifd = cifd;
253
254
if (c->fd == -1 || (c->fd != -1 && c->cifd != -1)) {
255
c->which = LAUNCHD_USE_CHECKIN_FD;
256
} else if (c->cifd == -1) {
257
c->which = LAUNCHD_USE_OTHER_FD;
258
}
259
260
fcntl(fd, F_SETFL, O_NONBLOCK);
261
fcntl(cifd, F_SETFL, O_NONBLOCK);
262
263
if ((c->sendbuf = malloc(0)) == NULL)
264
goto out_bad;
265
if ((c->sendfds = malloc(0)) == NULL)
266
goto out_bad;
267
if ((c->recvbuf = malloc(0)) == NULL)
268
goto out_bad;
269
if ((c->recvfds = malloc(0)) == NULL)
270
goto out_bad;
271
272
return c;
273
274
out_bad:
275
if (c->sendbuf)
276
free(c->sendbuf);
277
if (c->sendfds)
278
free(c->sendfds);
279
if (c->recvbuf)
280
free(c->recvbuf);
281
if (c->recvfds)
282
free(c->recvfds);
283
free(c);
284
return NULL;
285
}
286
287
void
288
launchd_close(launch_t lh, typeof(close) closefunc)
289
{
290
launch_globals_t globals = _launch_globals();
291
292
if (globals->in_flight_msg_recv_client == lh) {
293
globals->in_flight_msg_recv_client = NULL;
294
}
295
296
if (lh->sendbuf)
297
free(lh->sendbuf);
298
if (lh->sendfds)
299
free(lh->sendfds);
300
if (lh->recvbuf)
301
free(lh->recvbuf);
302
if (lh->recvfds)
303
free(lh->recvfds);
304
closefunc(lh->fd);
305
closefunc(lh->cifd);
306
free(lh);
307
}
308
309
int
310
launchd_msg_send(launch_t lh, launch_data_t d)
311
{
312
struct launch_msg_header lmh;
313
struct cmsghdr *cm = NULL;
314
struct msghdr mh;
315
struct iovec iov[2];
316
size_t sentctrllen = 0;
317
int r;
318
319
int fd2use = launchd_getfd(lh);
320
if (fd2use == -1) {
321
errno = EPERM;
322
return -1;
323
}
324
325
memset(&mh, 0, sizeof(mh));
326
327
/* confirm that the next hack works */
328
assert((d && lh->sendlen == 0) || (!d && lh->sendlen));
329
330
if (d) {
331
size_t fd_slots_used = 0;
332
size_t good_enough_size = 10 * 1024 * 1024;
333
uint64_t msglen;
334
335
/* hack, see the above assert to verify "correctness" */
336
free(lh->sendbuf);
337
lh->sendbuf = malloc(good_enough_size);
338
if (!lh->sendbuf) {
339
errno = ENOMEM;
340
return -1;
341
}
342
343
free(lh->sendfds);
344
lh->sendfds = malloc(4 * 1024);
345
if (!lh->sendfds) {
346
free(lh->sendbuf);
347
lh->sendbuf = NULL;
348
errno = ENOMEM;
349
return -1;
350
}
351
352
lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used);
353
354
if (lh->sendlen == 0) {
355
errno = ENOMEM;
356
return -1;
357
}
358
359
lh->sendfdcnt = fd_slots_used;
360
361
msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2wire() macro work right */
362
lmh.len = host2wire(msglen);
363
lmh.magic = host2wire(LAUNCH_MSG_HEADER_MAGIC);
364
365
iov[0].iov_base = &lmh;
366
iov[0].iov_len = sizeof(lmh);
367
mh.msg_iov = iov;
368
mh.msg_iovlen = 2;
369
} else {
370
mh.msg_iov = iov + 1;
371
mh.msg_iovlen = 1;
372
}
373
374
iov[1].iov_base = lh->sendbuf;
375
iov[1].iov_len = lh->sendlen;
376
377
378
if (lh->sendfdcnt > 0) {
379
sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int));
380
cm = alloca(mh.msg_controllen);
381
mh.msg_control = cm;
382
383
memset(cm, 0, mh.msg_controllen);
384
385
cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int));
386
cm->cmsg_level = SOL_SOCKET;
387
cm->cmsg_type = SCM_RIGHTS;
388
389
memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int));
390
}
391
392
if ((r = sendmsg(fd2use, &mh, 0)) == -1) {
393
return -1;
394
} else if (r == 0) {
395
errno = ECONNRESET;
396
return -1;
397
} else if (sentctrllen != mh.msg_controllen) {
398
errno = ECONNRESET;
399
return -1;
400
}
401
402
if (d) {
403
r -= sizeof(struct launch_msg_header);
404
}
405
406
lh->sendlen -= r;
407
if (lh->sendlen > 0) {
408
memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen);
409
} else {
410
free(lh->sendbuf);
411
lh->sendbuf = malloc(0);
412
}
413
414
lh->sendfdcnt = 0;
415
free(lh->sendfds);
416
lh->sendfds = malloc(0);
417
418
if (lh->sendlen > 0) {
419
errno = EAGAIN;
420
return -1;
421
}
422
423
return 0;
424
}
425
426
int
427
launch_get_fd(void)
428
{
429
launch_globals_t globals = _launch_globals();
430
pthread_once(&globals->lc_once, launch_client_init);
431
432
if (!globals->l) {
433
errno = ENOTCONN;
434
return -1;
435
}
436
437
return globals->l->fd;
438
}
439
440
void
441
launch_msg_getmsgs(launch_data_t m, void *context)
442
{
443
launch_data_t async_resp, *sync_resp = context;
444
445
launch_globals_t globals = _launch_globals();
446
447
if ((LAUNCH_DATA_DICTIONARY == launch_data_get_type(m)) && (async_resp = launch_data_dict_lookup(m, LAUNCHD_ASYNC_MSG_KEY))) {
448
launch_data_array_set_index(globals->async_resp, launch_data_copy(async_resp), launch_data_array_get_count(globals->async_resp));
449
} else {
450
*sync_resp = launch_data_copy(m);
451
}
452
}
453
454
#if HAS_MACH
455
void
456
launch_mach_checkin_service(launch_data_t obj, const char *key, void *context __attribute__((unused)))
457
{
458
kern_return_t result;
459
mach_port_t p;
460
name_t srvnm;
461
462
strlcpy(srvnm, key, sizeof(srvnm));
463
464
result = bootstrap_check_in(bootstrap_port, srvnm, &p);
465
466
if (result == BOOTSTRAP_SUCCESS)
467
launch_data_set_machport(obj, p);
468
}
469
#endif
470
471
launch_data_t
472
launch_msg(launch_data_t d)
473
{
474
launch_data_t mps, r = launch_msg_internal(d);
475
476
if (launch_data_get_type(d) == LAUNCH_DATA_STRING) {
477
if (strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) != 0)
478
return r;
479
if (r == NULL)
480
return r;
481
if (launch_data_get_type(r) != LAUNCH_DATA_DICTIONARY)
482
return r;
483
mps = launch_data_dict_lookup(r, LAUNCH_JOBKEY_MACHSERVICES);
484
if (mps == NULL)
485
return r;
486
#if HAS_MACH
487
launch_data_dict_iterate(mps, launch_mach_checkin_service, NULL);
488
#else
489
#pragma message "PORT: launch_data_dict_iterate inside of launch_msg()"
490
#endif
491
}
492
493
return r;
494
}
495
496
#if HAS_MACH
497
extern kern_return_t vproc_mig_set_security_session(mach_port_t, uuid_t, mach_port_t);
498
#endif
499
500
static inline bool
501
uuid_data_is_null(launch_data_t d)
502
{
503
bool result = false;
504
if (launch_data_get_type(d) == LAUNCH_DATA_OPAQUE && launch_data_get_opaque_size(d) == sizeof(uuid_t)) {
505
uuid_t existing_uuid;
506
memcpy(existing_uuid, launch_data_get_opaque(d), sizeof(uuid_t));
507
508
/* A NULL UUID tells us to keep the session inherited from the parent. */
509
result = (bool)uuid_is_null(existing_uuid);
510
}
511
512
return result;
513
}
514
515
launch_data_t
516
launch_msg_internal(launch_data_t d)
517
{
518
launch_data_t resp = NULL;
519
520
if (d && (launch_data_get_type(d) == LAUNCH_DATA_STRING)
521
&& (strcmp(launch_data_get_string(d), LAUNCH_KEY_GETJOBS) == 0)
522
&& vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) {
523
return resp;
524
}
525
526
launch_globals_t globals = _launch_globals();
527
pthread_once(&globals->lc_once, launch_client_init);
528
if (!globals->l) {
529
errno = ENOTCONN;
530
return NULL;
531
}
532
533
int fd2use = -1;
534
if ((launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0) || globals->s_am_embedded_god) {
535
globals->l->which = LAUNCHD_USE_CHECKIN_FD;
536
} else {
537
globals->l->which = LAUNCHD_USE_OTHER_FD;
538
}
539
540
fd2use = launchd_getfd(globals->l);
541
542
if (fd2use == -1) {
543
errno = EPERM;
544
return NULL;
545
}
546
547
#if !TARGET_OS_EMBEDDED
548
uuid_t uuid;
549
launch_data_t uuid_d = NULL;
550
size_t jobs_that_need_sessions = 0;
551
if (d && launch_data_get_type(d) == LAUNCH_DATA_DICTIONARY) {
552
launch_data_t v = launch_data_dict_lookup(d, LAUNCH_KEY_SUBMITJOB);
553
554
if (v && launch_data_get_type(v) == LAUNCH_DATA_ARRAY) {
555
size_t cnt = launch_data_array_get_count(v);
556
size_t i = 0;
557
558
uuid_generate(uuid);
559
for (i = 0; i < cnt; i++) {
560
launch_data_t ji = launch_data_array_get_index(v, i);
561
if (launch_data_get_type(ji) == LAUNCH_DATA_DICTIONARY) {
562
launch_data_t existing_v = launch_data_dict_lookup(ji, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
563
if (!existing_v) {
564
/* I really wish these were reference-counted. Sigh... */
565
uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
566
launch_data_dict_insert(ji, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
567
jobs_that_need_sessions++;
568
} else if (launch_data_get_type(existing_v) == LAUNCH_DATA_OPAQUE) {
569
jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
570
}
571
}
572
}
573
} else if (v && launch_data_get_type(v) == LAUNCH_DATA_DICTIONARY) {
574
launch_data_t existing_v = launch_data_dict_lookup(v, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
575
if (!existing_v) {
576
uuid_generate(uuid);
577
uuid_d = launch_data_new_opaque(uuid, sizeof(uuid));
578
launch_data_dict_insert(v, uuid_d, LAUNCH_JOBKEY_SECURITYSESSIONUUID);
579
jobs_that_need_sessions++;
580
} else {
581
jobs_that_need_sessions += uuid_data_is_null(existing_v) ? 0 : 1;
582
}
583
}
584
}
585
#endif
586
587
pthread_mutex_lock(&globals->lc_mtx);
588
589
if (d && launchd_msg_send(globals->l, d) == -1) {
590
do {
591
if (errno != EAGAIN)
592
goto out;
593
} while (launchd_msg_send(globals->l, NULL) == -1);
594
}
595
596
while (resp == NULL) {
597
if (d == NULL && launch_data_array_get_count(globals->async_resp) > 0) {
598
resp = launch_data_array_pop_first(globals->async_resp);
599
goto out;
600
}
601
if (launchd_msg_recv(globals->l, launch_msg_getmsgs, &resp) == -1) {
602
if (errno != EAGAIN) {
603
goto out;
604
} else if (d == NULL) {
605
errno = 0;
606
goto out;
607
} else {
608
fd_set rfds;
609
610
FD_ZERO(&rfds);
611
FD_SET(fd2use, &rfds);
612
613
select(fd2use + 1, &rfds, NULL, NULL, NULL);
614
}
615
}
616
}
617
618
out:
619
#if !TARGET_OS_EMBEDDED && __APPLE__
620
if (!uuid_is_null(uuid) && resp && jobs_that_need_sessions > 0) {
621
mach_port_t session_port = _audit_session_self();
622
launch_data_type_t resp_type = launch_data_get_type(resp);
623
624
bool set_session = false;
625
if (resp_type == LAUNCH_DATA_ERRNO) {
626
set_session = (launch_data_get_errno(resp) == ENEEDAUTH);
627
} else if (resp_type == LAUNCH_DATA_ARRAY) {
628
set_session = true;
629
}
630
631
kern_return_t kr = KERN_FAILURE;
632
if (set_session) {
633
kr = vproc_mig_set_security_session(bootstrap_port, uuid, session_port);
634
}
635
636
if (kr == KERN_SUCCESS) {
637
if (resp_type == LAUNCH_DATA_ERRNO) {
638
launch_data_set_errno(resp, 0);
639
} else {
640
size_t i = 0;
641
for (i = 0; i < launch_data_array_get_count(resp); i++) {
642
launch_data_t ri = launch_data_array_get_index(resp, i);
643
644
int recvd_err = 0;
645
if (launch_data_get_type(ri) == LAUNCH_DATA_ERRNO && (recvd_err = launch_data_get_errno(ri))) {
646
launch_data_set_errno(ri, recvd_err == ENEEDAUTH ? 0 : recvd_err);
647
}
648
}
649
}
650
}
651
652
mach_port_deallocate(mach_task_self(), session_port);
653
}
654
#else
655
#pragma message "PORT: launch_msg_internal() temporarily skipping over some handling"
656
#endif
657
658
pthread_mutex_unlock(&globals->lc_mtx);
659
660
return resp;
661
}
662
663
int
664
launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
665
{
666
struct cmsghdr *cm = alloca(4096);
667
launch_data_t rmsg = NULL;
668
size_t data_offset, fd_offset;
669
struct msghdr mh;
670
struct iovec iov;
671
int r;
672
673
int fd2use = launchd_getfd(lh);
674
if (fd2use == -1) {
675
errno = EPERM;
676
return -1;
677
}
678
679
memset(&mh, 0, sizeof(mh));
680
mh.msg_iov = &iov;
681
mh.msg_iovlen = 1;
682
683
lh->recvbuf = reallocf(lh->recvbuf, lh->recvlen + 8*1024);
684
685
iov.iov_base = lh->recvbuf + lh->recvlen;
686
iov.iov_len = 8*1024;
687
mh.msg_control = cm;
688
mh.msg_controllen = 4096;
689
690
if ((r = recvmsg(fd2use, &mh, 0)) == -1)
691
return -1;
692
if (r == 0) {
693
errno = ECONNRESET;
694
return -1;
695
}
696
if (mh.msg_flags & MSG_CTRUNC) {
697
errno = ECONNABORTED;
698
return -1;
699
}
700
lh->recvlen += r;
701
if (mh.msg_controllen > 0) {
702
lh->recvfds = reallocf(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr));
703
memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr));
704
lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
705
}
706
707
r = 0;
708
709
while (lh->recvlen > 0) {
710
struct launch_msg_header *lmhp = lh->recvbuf;
711
uint64_t tmplen;
712
data_offset = sizeof(struct launch_msg_header);
713
fd_offset = 0;
714
715
if (lh->recvlen < sizeof(struct launch_msg_header))
716
goto need_more_data;
717
718
tmplen = wire2host(lmhp->len);
719
720
if (wire2host(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) {
721
errno = EBADRPC;
722
goto out_bad;
723
}
724
725
if (lh->recvlen < tmplen) {
726
goto need_more_data;
727
}
728
729
if ((rmsg = launch_data_unpack(lh->recvbuf, lh->recvlen, lh->recvfds, lh->recvfdcnt, &data_offset, &fd_offset)) == NULL) {
730
errno = EBADRPC;
731
goto out_bad;
732
}
733
734
launch_globals_t globals = _launch_globals();
735
736
globals->in_flight_msg_recv_client = lh;
737
738
cb(rmsg, context);
739
740
/* launchd and only launchd can call launchd_close() as a part of the callback */
741
if (globals->in_flight_msg_recv_client == NULL) {
742
r = 0;
743
break;
744
}
745
746
lh->recvlen -= data_offset;
747
if (lh->recvlen > 0) {
748
memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen);
749
} else {
750
free(lh->recvbuf);
751
lh->recvbuf = malloc(0);
752
}
753
754
lh->recvfdcnt -= fd_offset;
755
if (lh->recvfdcnt > 0) {
756
memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int));
757
} else {
758
free(lh->recvfds);
759
lh->recvfds = malloc(0);
760
}
761
}
762
763
return r;
764
765
need_more_data:
766
errno = EAGAIN;
767
out_bad:
768
return -1;
769
}
770
771
launch_data_t
772
launch_data_copy(launch_data_t o)
773
{
774
launch_data_t r = launch_data_alloc(o->type);
775
size_t i;
776
777
free(r->_array);
778
memcpy(r, o, sizeof(struct _launch_data));
779
780
switch (o->type) {
781
case LAUNCH_DATA_DICTIONARY:
782
case LAUNCH_DATA_ARRAY:
783
r->_array = calloc(1, o->_array_cnt * sizeof(launch_data_t));
784
for (i = 0; i < o->_array_cnt; i++) {
785
if (o->_array[i])
786
r->_array[i] = launch_data_copy(o->_array[i]);
787
}
788
break;
789
case LAUNCH_DATA_STRING:
790
r->string = strdup(o->string);
791
break;
792
case LAUNCH_DATA_OPAQUE:
793
r->opaque = malloc(o->opaque_size);
794
memcpy(r->opaque, o->opaque, o->opaque_size);
795
break;
796
default:
797
break;
798
}
799
800
return r;
801
}
802
803
launch_data_t
804
launch_data_new_errno(int e)
805
{
806
launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
807
808
if (r)
809
launch_data_set_errno(r, e);
810
811
return r;
812
}
813
814
launch_data_t
815
launch_data_new_fd(int fd)
816
{
817
launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
818
819
if (r)
820
launch_data_set_fd(r, fd);
821
822
return r;
823
}
824
825
#if HAS_MOCH
826
launch_data_t
827
launch_data_new_machport(mach_port_t p)
828
{
829
launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT);
830
831
if (r)
832
launch_data_set_machport(r, p);
833
834
return r;
835
}
836
#endif
837
838
launch_data_t
839
launch_data_new_integer(long long n)
840
{
841
launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER);
842
843
if (r)
844
launch_data_set_integer(r, n);
845
846
return r;
847
}
848
849
launch_data_t
850
launch_data_new_bool(bool b)
851
{
852
launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL);
853
854
if (r)
855
launch_data_set_bool(r, b);
856
857
return r;
858
}
859
860
launch_data_t
861
launch_data_new_real(double d)
862
{
863
launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL);
864
865
if (r)
866
launch_data_set_real(r, d);
867
868
return r;
869
}
870
871
launch_data_t
872
launch_data_new_string(const char *s)
873
{
874
launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING);
875
876
if (r == NULL)
877
return NULL;
878
879
if (!launch_data_set_string(r, s)) {
880
launch_data_free(r);
881
return NULL;
882
}
883
884
return r;
885
}
886
887
launch_data_t
888
launch_data_new_opaque(const void *o, size_t os)
889
{
890
launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
891
892
if (r == NULL)
893
return NULL;
894
895
if (!launch_data_set_opaque(r, o, os)) {
896
launch_data_free(r);
897
return NULL;
898
}
899
900
return r;
901
}
902
903
#ifdef __APPLE__
904
/*
905
* This is not likely necessary anywhere but Apple OSes right now
906
*/
907
void
908
load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...)
909
{
910
_vprocmgr_init(VPROCMGR_SESSION_LOGINWINDOW);
911
}
912
913
pid_t
914
create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags, ...)
915
{
916
uid_t target_user = geteuid() ? geteuid() : getuid();
917
if (_vprocmgr_move_subset_to_user(target_user, VPROCMGR_SESSION_AQUA, flags)) {
918
return -1;
919
}
920
921
return 1;
922
}
923
#endif
924
925
#endif /* UNIT_TEST */
926
927