]>
Commit | Line | Data |
---|---|---|
ed34e3c3 A |
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 | ||
5b0a4722 | 21 | #include "config.h" |
eabd1701 | 22 | #include "ipc.h" |
ed34e3c3 | 23 | |
ddbbfbc1 | 24 | #include <sys/socket.h> |
ed34e3c3 A |
25 | #include <sys/types.h> |
26 | #include <sys/queue.h> | |
27 | #include <sys/event.h> | |
28 | #include <sys/stat.h> | |
29 | #include <sys/ucred.h> | |
30 | #include <sys/fcntl.h> | |
31 | #include <sys/un.h> | |
32 | #include <sys/wait.h> | |
33 | #include <sys/sysctl.h> | |
34 | #include <sys/sockio.h> | |
35 | #include <sys/time.h> | |
36 | #include <sys/resource.h> | |
37 | #include <sys/ioctl.h> | |
38 | #include <unistd.h> | |
39 | #include <signal.h> | |
40 | #include <errno.h> | |
ed34e3c3 A |
41 | #include <libgen.h> |
42 | #include <stdio.h> | |
43 | #include <stdlib.h> | |
44 | #include <stdarg.h> | |
45 | #include <stdbool.h> | |
46 | #include <paths.h> | |
47 | #include <string.h> | |
95379394 | 48 | #include <os/assumes.h> |
ed34e3c3 | 49 | |
ef398931 A |
50 | #include "launch.h" |
51 | #include "launch_priv.h" | |
ed34e3c3 | 52 | #include "launchd.h" |
eabd1701 A |
53 | #include "runtime.h" |
54 | #include "core.h" | |
ed34e3c3 A |
55 | |
56 | extern char **environ; | |
57 | ||
5b0a4722 | 58 | static LIST_HEAD(, conncb) connections; |
ed34e3c3 A |
59 | |
60 | static launch_data_t adjust_rlimits(launch_data_t in); | |
61 | ||
62 | static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context); | |
ddbbfbc1 | 63 | static void ipc_readmsg(launch_data_t msg, void *context); |
ed34e3c3 A |
64 | |
65 | static void ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev); | |
66 | ||
67 | static kq_callback kqipc_listen_callback = ipc_listen_callback; | |
68 | ||
69 | static pid_t ipc_self = 0; | |
70 | ||
71 | char *sockpath = NULL; | |
72 | static char *sockdir = NULL; | |
73 | ||
74 | static bool ipc_inited = false; | |
75 | ||
ddbbfbc1 | 76 | static void |
ed34e3c3 A |
77 | ipc_clean_up(void) |
78 | { | |
5b0a4722 | 79 | if (ipc_self != getpid()) { |
ed34e3c3 | 80 | return; |
5b0a4722 | 81 | } |
ed34e3c3 | 82 | |
5b0a4722 | 83 | if (-1 == unlink(sockpath)) { |
eabd1701 | 84 | launchd_syslog(LOG_WARNING, "unlink(\"%s\"): %s", sockpath, strerror(errno)); |
5b0a4722 | 85 | } else if (-1 == rmdir(sockdir)) { |
eabd1701 | 86 | launchd_syslog(LOG_WARNING, "rmdir(\"%s\"): %s", sockdir, strerror(errno)); |
5b0a4722 | 87 | } |
ed34e3c3 A |
88 | } |
89 | ||
90 | void | |
5b0a4722 | 91 | ipc_server_init(void) |
ed34e3c3 A |
92 | { |
93 | struct sockaddr_un sun; | |
94 | mode_t oldmask; | |
95 | int r, fd = -1; | |
96 | char ourdir[1024]; | |
ed34e3c3 | 97 | |
5b0a4722 | 98 | if (ipc_inited) { |
ed34e3c3 | 99 | return; |
5b0a4722 | 100 | } |
ed34e3c3 A |
101 | |
102 | memset(&sun, 0, sizeof(sun)); | |
103 | sun.sun_family = AF_UNIX; | |
104 | ||
ddbbfbc1 | 105 | if (pid1_magic) { |
ed34e3c3 A |
106 | strcpy(ourdir, LAUNCHD_SOCK_PREFIX); |
107 | strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); | |
108 | ||
109 | unlink(ourdir); | |
110 | if (mkdir(ourdir, S_IRWXU) == -1) { | |
111 | if (errno == EROFS) { | |
112 | goto out_bad; | |
113 | } else if (errno == EEXIST) { | |
114 | struct stat sb; | |
115 | stat(ourdir, &sb); | |
116 | if (!S_ISDIR(sb.st_mode)) { | |
117 | errno = EEXIST; | |
eabd1701 | 118 | launchd_syslog(LOG_ERR, "mkdir(\"%s\"): %s", LAUNCHD_SOCK_PREFIX, strerror(errno)); |
ed34e3c3 A |
119 | goto out_bad; |
120 | } | |
121 | } else { | |
eabd1701 | 122 | launchd_syslog(LOG_ERR, "mkdir(\"%s\"): %s", ourdir, strerror(errno)); |
ed34e3c3 A |
123 | goto out_bad; |
124 | } | |
125 | } | |
126 | } else { | |
ddbbfbc1 A |
127 | snprintf(ourdir, sizeof(ourdir), _PATH_TMP "launchd-%u.XXXXXX", getpid()); |
128 | if (mkdtemp(ourdir) == NULL) { | |
eabd1701 | 129 | launchd_syslog(LOG_ERR, "Could not create critical directory \"%s\": %s", ourdir, strerror(errno)); |
ed34e3c3 | 130 | goto out_bad; |
5b0a4722 | 131 | } |
ed34e3c3 | 132 | snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/sock", ourdir); |
ed34e3c3 A |
133 | } |
134 | ||
135 | if (unlink(sun.sun_path) == -1 && errno != ENOENT) { | |
5b0a4722 | 136 | if (errno != EROFS) { |
eabd1701 | 137 | launchd_syslog(LOG_ERR, "unlink(\"thesocket\"): %s", strerror(errno)); |
5b0a4722 | 138 | } |
ed34e3c3 A |
139 | goto out_bad; |
140 | } | |
141 | ||
eabd1701 | 142 | if (posix_assumes_zero(fd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) { |
ed34e3c3 | 143 | goto out_bad; |
5b0a4722 | 144 | } |
ed34e3c3 A |
145 | |
146 | oldmask = umask(S_IRWXG|S_IRWXO); | |
147 | r = bind(fd, (struct sockaddr *)&sun, sizeof(sun)); | |
148 | umask(oldmask); | |
149 | ||
150 | if (r == -1) { | |
5b0a4722 | 151 | if (errno != EROFS) { |
eabd1701 | 152 | launchd_syslog(LOG_ERR, "bind(\"thesocket\"): %s", strerror(errno)); |
5b0a4722 | 153 | } |
ed34e3c3 A |
154 | goto out_bad; |
155 | } | |
156 | ||
157 | if (listen(fd, SOMAXCONN) == -1) { | |
eabd1701 | 158 | launchd_syslog(LOG_ERR, "listen(\"thesocket\"): %s", strerror(errno)); |
ed34e3c3 A |
159 | goto out_bad; |
160 | } | |
161 | ||
5b0a4722 | 162 | if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { |
eabd1701 | 163 | launchd_syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %s", strerror(errno)); |
ed34e3c3 A |
164 | goto out_bad; |
165 | } | |
166 | ||
167 | ipc_inited = true; | |
168 | ||
5b0a4722 A |
169 | sockdir = strdup(ourdir); |
170 | sockpath = strdup(sun.sun_path); | |
171 | ipc_self = getpid(); | |
172 | atexit(ipc_clean_up); | |
ed34e3c3 A |
173 | |
174 | out_bad: | |
5b0a4722 | 175 | if (!ipc_inited && fd != -1) { |
eabd1701 | 176 | (void)runtime_close(fd); |
5b0a4722 | 177 | } |
ed34e3c3 A |
178 | } |
179 | ||
180 | void | |
5b0a4722 | 181 | ipc_open(int fd, job_t j) |
ed34e3c3 A |
182 | { |
183 | struct conncb *c = calloc(1, sizeof(struct conncb)); | |
184 | ||
185 | fcntl(fd, F_SETFL, O_NONBLOCK); | |
186 | ||
187 | c->kqconn_callback = ipc_callback; | |
dcace88f | 188 | if (j) { |
ddbbfbc1 A |
189 | c->conn = launchd_fdopen(-1, fd); |
190 | } else { | |
191 | c->conn = launchd_fdopen(fd, -1); | |
192 | } | |
eabd1701 | 193 | |
ed34e3c3 | 194 | c->j = j; |
5b0a4722 | 195 | LIST_INSERT_HEAD(&connections, c, sle); |
ed34e3c3 A |
196 | kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback); |
197 | } | |
198 | ||
199 | void | |
200 | ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev) | |
201 | { | |
202 | struct sockaddr_un sun; | |
203 | socklen_t sl = sizeof(sun); | |
204 | int cfd; | |
205 | ||
206 | if ((cfd = _fd(accept(kev->ident, (struct sockaddr *)&sun, &sl))) == -1) { | |
207 | return; | |
208 | } | |
209 | ||
95379394 A |
210 | if (geteuid() == 0) { |
211 | uid_t euid, guid; | |
212 | if (getpeereid(cfd, &euid, &guid) == -1) { | |
213 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[%d] failed to getpeereid on incoming caller (%d)", getpid(), errno); | |
214 | (void)runtime_close(cfd); | |
215 | return; | |
216 | } | |
217 | ||
218 | if (euid != geteuid()) { | |
219 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[%d] failed to euid check on incoming caller (%d != %d)", getpid(), euid, geteuid()); | |
220 | (void)runtime_close(cfd); | |
221 | return; | |
222 | } | |
223 | } | |
224 | ||
ed34e3c3 A |
225 | ipc_open(cfd, NULL); |
226 | } | |
227 | ||
228 | void | |
229 | ipc_callback(void *obj, struct kevent *kev) | |
230 | { | |
231 | struct conncb *c = obj; | |
232 | int r; | |
eabd1701 | 233 | |
ed34e3c3 A |
234 | if (kev->filter == EVFILT_READ) { |
235 | if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) { | |
5b0a4722 | 236 | if (errno != ECONNRESET) { |
eabd1701 | 237 | launchd_syslog(LOG_DEBUG, "%s(): recv: %s", __func__, strerror(errno)); |
5b0a4722 | 238 | } |
ed34e3c3 A |
239 | ipc_close(c); |
240 | } | |
241 | } else if (kev->filter == EVFILT_WRITE) { | |
242 | r = launchd_msg_send(c->conn, NULL); | |
243 | if (r == -1) { | |
244 | if (errno != EAGAIN) { | |
eabd1701 | 245 | launchd_syslog(LOG_DEBUG, "%s(): send: %s", __func__, strerror(errno)); |
ed34e3c3 A |
246 | ipc_close(c); |
247 | } | |
248 | } else if (r == 0) { | |
249 | kevent_mod(launchd_getfd(c->conn), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); | |
250 | } | |
251 | } else { | |
eabd1701 | 252 | launchd_syslog(LOG_DEBUG, "%s(): unknown filter type!", __func__); |
ed34e3c3 A |
253 | ipc_close(c); |
254 | } | |
255 | } | |
256 | ||
ddbbfbc1 A |
257 | static void |
258 | set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) | |
ed34e3c3 | 259 | { |
ddbbfbc1 | 260 | const char *v = launch_data_get_string(obj); |
dcace88f | 261 | if (v) { |
ddbbfbc1 A |
262 | setenv(key, v, 1); |
263 | } else { | |
eabd1701 | 264 | launchd_syslog(LOG_WARNING, "Attempt to set NULL environment variable: %s (type = %d)", key, launch_data_get_type(obj)); |
ddbbfbc1 | 265 | } |
ed34e3c3 A |
266 | } |
267 | ||
5b0a4722 A |
268 | void |
269 | ipc_close_all_with_job(job_t j) | |
270 | { | |
271 | struct conncb *ci, *cin; | |
272 | ||
273 | LIST_FOREACH_SAFE(ci, &connections, sle, cin) { | |
274 | if (ci->j == j) { | |
275 | ipc_close(ci); | |
276 | } | |
277 | } | |
278 | } | |
279 | ||
ed34e3c3 A |
280 | void |
281 | ipc_close_fds(launch_data_t o) | |
282 | { | |
283 | size_t i; | |
284 | ||
285 | switch (launch_data_get_type(o)) { | |
286 | case LAUNCH_DATA_DICTIONARY: | |
287 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_close_fds, NULL); | |
288 | break; | |
289 | case LAUNCH_DATA_ARRAY: | |
290 | for (i = 0; i < launch_data_array_get_count(o); i++) | |
291 | ipc_close_fds(launch_data_array_get_index(o, i)); | |
292 | break; | |
293 | case LAUNCH_DATA_FD: | |
5b0a4722 | 294 | if (launch_data_get_fd(o) != -1) { |
eabd1701 | 295 | (void)runtime_close(launch_data_get_fd(o)); |
5b0a4722 | 296 | } |
ed34e3c3 A |
297 | break; |
298 | default: | |
299 | break; | |
300 | } | |
301 | } | |
302 | ||
303 | void | |
304 | ipc_revoke_fds(launch_data_t o) | |
305 | { | |
306 | size_t i; | |
307 | ||
308 | switch (launch_data_get_type(o)) { | |
309 | case LAUNCH_DATA_DICTIONARY: | |
310 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_revoke_fds, NULL); | |
311 | break; | |
312 | case LAUNCH_DATA_ARRAY: | |
313 | for (i = 0; i < launch_data_array_get_count(o); i++) | |
314 | ipc_revoke_fds(launch_data_array_get_index(o, i)); | |
315 | break; | |
316 | case LAUNCH_DATA_FD: | |
317 | launch_data_set_fd(o, -1); | |
318 | break; | |
319 | default: | |
320 | break; | |
321 | } | |
322 | } | |
323 | ||
324 | struct readmsg_context { | |
325 | struct conncb *c; | |
326 | launch_data_t resp; | |
327 | }; | |
328 | ||
329 | void | |
330 | ipc_readmsg(launch_data_t msg, void *context) | |
331 | { | |
332 | struct readmsg_context rmc = { context, NULL }; | |
333 | ||
334 | if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(msg)) { | |
335 | launch_data_dict_iterate(msg, ipc_readmsg2, &rmc); | |
336 | } else if (LAUNCH_DATA_STRING == launch_data_get_type(msg)) { | |
337 | ipc_readmsg2(NULL, launch_data_get_string(msg), &rmc); | |
338 | } else { | |
339 | rmc.resp = launch_data_new_errno(EINVAL); | |
340 | } | |
341 | ||
5b0a4722 | 342 | if (NULL == rmc.resp) { |
ed34e3c3 | 343 | rmc.resp = launch_data_new_errno(ENOSYS); |
5b0a4722 | 344 | } |
ed34e3c3 A |
345 | |
346 | ipc_close_fds(msg); | |
347 | ||
348 | if (launchd_msg_send(rmc.c->conn, rmc.resp) == -1) { | |
349 | if (errno == EAGAIN) { | |
350 | kevent_mod(launchd_getfd(rmc.c->conn), EVFILT_WRITE, EV_ADD, 0, 0, &rmc.c->kqconn_callback); | |
351 | } else { | |
eabd1701 | 352 | launchd_syslog(LOG_DEBUG, "launchd_msg_send() == -1: %s", strerror(errno)); |
ed34e3c3 A |
353 | ipc_close(rmc.c); |
354 | } | |
355 | } | |
356 | launch_data_free(rmc.resp); | |
357 | } | |
358 | ||
ed34e3c3 A |
359 | void |
360 | ipc_readmsg2(launch_data_t data, const char *cmd, void *context) | |
361 | { | |
362 | struct readmsg_context *rmc = context; | |
363 | launch_data_t resp = NULL; | |
5b0a4722 | 364 | job_t j; |
ed34e3c3 | 365 | |
5b0a4722 | 366 | if (rmc->resp) { |
ed34e3c3 | 367 | return; |
5b0a4722 A |
368 | } |
369 | ||
ddbbfbc1 | 370 | /* Do not allow commands other than check-in to come over the trusted socket |
eabd1701 A |
371 | * on the Desktop. On Embedded, allow all commands over the trusted socket |
372 | * if the job has the God Mode key set. | |
ddbbfbc1 A |
373 | */ |
374 | #if TARGET_OS_EMBEDDED | |
eabd1701 | 375 | bool allow_privileged_ops = (!rmc->c->j || job_is_god(rmc->c->j)); |
ddbbfbc1 A |
376 | #else |
377 | bool allow_privileged_ops = !rmc->c->j; | |
378 | #endif | |
eabd1701 | 379 | |
dcace88f | 380 | if (rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0) { |
ddbbfbc1 A |
381 | resp = job_export(rmc->c->j); |
382 | job_checkin(rmc->c->j); | |
dcace88f | 383 | } else if (allow_privileged_ops) { |
eabd1701 A |
384 | #if TARGET_OS_EMBEDDED |
385 | launchd_embedded_handofgod = rmc->c->j && job_is_god(rmc->c->j); | |
386 | #endif | |
dcace88f | 387 | if (data == NULL) { |
ddbbfbc1 A |
388 | if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { |
389 | launchd_shutdown(); | |
390 | resp = launch_data_new_errno(0); | |
ddbbfbc1 A |
391 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { |
392 | resp = job_export_all(); | |
393 | ipc_revoke_fds(resp); | |
394 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { | |
395 | resp = adjust_rlimits(NULL); | |
396 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { | |
397 | struct rusage rusage; | |
398 | getrusage(RUSAGE_SELF, &rusage); | |
399 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); | |
400 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { | |
401 | struct rusage rusage; | |
402 | getrusage(RUSAGE_CHILDREN, &rusage); | |
403 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); | |
ed34e3c3 | 404 | } |
ed34e3c3 | 405 | } else { |
ddbbfbc1 | 406 | if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { |
dcace88f | 407 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { |
ddbbfbc1 A |
408 | errno = job_dispatch(j, true) ? 0 : errno; |
409 | } | |
410 | resp = launch_data_new_errno(errno); | |
411 | } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { | |
dcace88f | 412 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { |
ddbbfbc1 A |
413 | errno = 0; |
414 | job_stop(j); | |
415 | } | |
416 | resp = launch_data_new_errno(errno); | |
417 | } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { | |
dcace88f | 418 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { |
ddbbfbc1 A |
419 | errno = 0; |
420 | job_remove(j); | |
421 | } | |
422 | resp = launch_data_new_errno(errno); | |
423 | } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { | |
424 | if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { | |
425 | resp = job_import_bulk(data); | |
426 | } else { | |
427 | if (job_import(data)) { | |
428 | errno = 0; | |
429 | } | |
430 | resp = launch_data_new_errno(errno); | |
431 | } | |
432 | } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { | |
433 | unsetenv(launch_data_get_string(data)); | |
434 | resp = launch_data_new_errno(0); | |
435 | } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { | |
436 | launch_data_dict_iterate(data, set_user_env, NULL); | |
437 | resp = launch_data_new_errno(0); | |
438 | } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { | |
439 | resp = adjust_rlimits(data); | |
440 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { | |
dcace88f | 441 | if ((j = job_find(NULL, launch_data_get_string(data))) == NULL) { |
ddbbfbc1 A |
442 | resp = launch_data_new_errno(errno); |
443 | } else { | |
444 | resp = job_export(j); | |
445 | ipc_revoke_fds(resp); | |
446 | } | |
5b0a4722 | 447 | } |
ed34e3c3 | 448 | } |
eabd1701 A |
449 | #if TARGET_OS_EMBEDDED |
450 | launchd_embedded_handofgod = false; | |
451 | #endif | |
ddbbfbc1 A |
452 | } else { |
453 | resp = launch_data_new_errno(EACCES); | |
ed34e3c3 A |
454 | } |
455 | ||
456 | rmc->resp = resp; | |
457 | } | |
458 | ||
ddbbfbc1 A |
459 | static int |
460 | close_abi_fixup(int fd) | |
461 | { | |
462 | return runtime_close(fd); | |
463 | } | |
464 | ||
ed34e3c3 A |
465 | void |
466 | ipc_close(struct conncb *c) | |
467 | { | |
5b0a4722 | 468 | LIST_REMOVE(c, sle); |
ddbbfbc1 | 469 | launchd_close(c->conn, close_abi_fixup); |
ed34e3c3 A |
470 | free(c); |
471 | } | |
472 | ||
473 | launch_data_t | |
474 | adjust_rlimits(launch_data_t in) | |
475 | { | |
eabd1701 A |
476 | /* If I never have to deal with this rlimit nonsense again, I'll be a very |
477 | * happy man. | |
478 | */ | |
ed34e3c3 A |
479 | struct rlimit l[RLIM_NLIMITS]; |
480 | struct rlimit *ltmp; | |
481 | size_t i,ltmpsz; | |
482 | ||
483 | for (i = 0; i < RLIM_NLIMITS; i++) { | |
eabd1701 | 484 | (void)posix_assumes_zero(getrlimit(i, l + i)); |
ed34e3c3 A |
485 | } |
486 | ||
487 | if (in) { | |
488 | ltmp = launch_data_get_opaque(in); | |
489 | ltmpsz = launch_data_get_opaque_size(in); | |
490 | ||
491 | if (ltmpsz > sizeof(l)) { | |
eabd1701 | 492 | launchd_syslog(LOG_WARNING, "Too much rlimit data sent!"); |
ed34e3c3 A |
493 | ltmpsz = sizeof(l); |
494 | } | |
eabd1701 | 495 | |
ed34e3c3 | 496 | for (i = 0; i < (ltmpsz / sizeof(struct rlimit)); i++) { |
5b0a4722 | 497 | if (ltmp[i].rlim_cur == l[i].rlim_cur && ltmp[i].rlim_max == l[i].rlim_max) { |
ed34e3c3 | 498 | continue; |
5b0a4722 | 499 | } |
ed34e3c3 | 500 | |
ddbbfbc1 | 501 | if (/* XXX readcfg_pid && */ pid1_magic && (i == RLIMIT_NOFILE || i == RLIMIT_NPROC)) { |
ed34e3c3 A |
502 | int gmib[] = { CTL_KERN, KERN_MAXPROC }; |
503 | int pmib[] = { CTL_KERN, KERN_MAXPROCPERUID }; | |
504 | const char *gstr = "kern.maxproc"; | |
505 | const char *pstr = "kern.maxprocperuid"; | |
506 | int gval = ltmp[i].rlim_max; | |
507 | int pval = ltmp[i].rlim_cur; | |
508 | switch (i) { | |
509 | case RLIMIT_NOFILE: | |
510 | gmib[1] = KERN_MAXFILES; | |
511 | pmib[1] = KERN_MAXFILESPERPROC; | |
512 | gstr = "kern.maxfiles"; | |
513 | pstr = "kern.maxfilesperproc"; | |
514 | break; | |
ed34e3c3 A |
515 | default: |
516 | break; | |
517 | } | |
518 | ||
519 | if (gval > 0) { | |
eabd1701 | 520 | (void)posix_assumes_zero(sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval))); |
ed34e3c3 | 521 | } else { |
eabd1701 | 522 | launchd_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", gstr); |
ed34e3c3 A |
523 | } |
524 | if (pval > 0) { | |
eabd1701 | 525 | (void)posix_assumes_zero(sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval))); |
ed34e3c3 | 526 | } else { |
eabd1701 | 527 | launchd_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", pstr); |
ed34e3c3 A |
528 | } |
529 | } | |
eabd1701 | 530 | (void)posix_assumes_zero(setrlimit(i, ltmp + i)); |
ed34e3c3 | 531 | /* the kernel may have clamped the values we gave it */ |
eabd1701 | 532 | (void)posix_assumes_zero(getrlimit(i, l + i)); |
ed34e3c3 A |
533 | } |
534 | } | |
535 | ||
536 | return launch_data_new_opaque(l, sizeof(struct rlimit) * RLIM_NLIMITS); | |
537 | } |