]> git.saurik.com Git - apple/launchd.git/blame - support/launchproxy.c
launchd-842.92.1.tar.gz
[apple/launchd.git] / support / launchproxy.c
CommitLineData
e91b9f68
A
1/*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
ed34e3c3 4 * @APPLE_APACHE_LICENSE_HEADER_START@
e91b9f68 5 *
ed34e3c3
A
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
e91b9f68 9 *
ed34e3c3
A
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
e91b9f68
A
16 * limitations under the License.
17 *
ed34e3c3 18 * @APPLE_APACHE_LICENSE_HEADER_END@
e91b9f68 19 */
f36da725 20#include "config.h"
e91b9f68
A
21#include <sys/types.h>
22#include <sys/select.h>
23#include <sys/event.h>
24#include <sys/socket.h>
25#include <sys/time.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <stdbool.h>
29#include <unistd.h>
30#include <string.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <syslog.h>
34#include <libgen.h>
35#include <getopt.h>
36#include <signal.h>
37#include <netdb.h>
38
dcace88f
A
39#if !TARGET_OS_EMBEDDED
40#include <bsm/audit.h>
41#include <bsm/audit_session.h>
5c88273d 42#endif // !TARGET_OS_EMBEDDED
aa59983a 43
dcace88f
A
44#include "launch.h"
45
e91b9f68
A
46static int kq = 0;
47
48static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused)))
49{
5b0a4722
A
50 struct kevent kev;
51 size_t i;
e91b9f68
A
52 int fd;
53
5b0a4722
A
54 switch (launch_data_get_type(o)) {
55 case LAUNCH_DATA_FD:
e91b9f68
A
56 fd = launch_data_get_fd(o);
57 if (-1 == fd)
58 break;
ed34e3c3 59 fcntl(fd, F_SETFD, 1);
e91b9f68 60 EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
ed34e3c3
A
61 if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1)
62 syslog(LOG_DEBUG, "kevent(%d): %m", fd);
5b0a4722
A
63 break;
64 case LAUNCH_DATA_ARRAY:
65 for (i = 0; i < launch_data_array_get_count(o); i++)
66 find_fds(launch_data_array_get_index(o, i), NULL, NULL);
67 break;
68 case LAUNCH_DATA_DICTIONARY:
69 launch_data_dict_iterate(o, find_fds, NULL);
70 break;
71 default:
72 break;
73 }
e91b9f68
A
74}
75
76int main(int argc __attribute__((unused)), char *argv[])
77{
ed34e3c3 78 struct timespec timeout = { 10, 0 };
e91b9f68 79 struct sockaddr_storage ss;
ddbbfbc1 80 socklen_t slen = (socklen_t)sizeof ss;
e91b9f68
A
81 struct kevent kev;
82 int r, ec = EXIT_FAILURE;
83 launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
84 const char *prog = argv[1];
85 bool w = false, dupstdout = true, dupstderr = true;
86
87 launch_data_set_string(msg, LAUNCH_KEY_CHECKIN);
88
89 openlog(getprogname(), LOG_PERROR|LOG_PID|LOG_CONS, LOG_LAUNCHD);
90
91 kq = kqueue();
92
93 if ((resp = launch_msg(msg)) == NULL) {
94 syslog(LOG_ERR, "launch_msg(%s): %m", LAUNCH_KEY_CHECKIN);
95 goto out;
96 }
97
98 launch_data_free(msg);
99
100 tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
101 if (tmp) {
102 find_fds(tmp, NULL, NULL);
103 } else {
104 syslog(LOG_ERR, "No FDs found to answer requests on!");
105 goto out;
106 }
107
108 tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT);
109 if (tmp)
5b0a4722 110 timeout.tv_sec = (int)launch_data_get_integer(tmp);
e91b9f68
A
111
112 tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_PROGRAM);
113 if (tmp)
114 prog = launch_data_get_string(tmp);
115
116 tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_INETDCOMPATIBILITY);
117 if (tmp) {
118 tmp = launch_data_dict_lookup(tmp, LAUNCH_JOBINETDCOMPATIBILITY_WAIT);
119 if (tmp)
120 w = launch_data_get_bool(tmp);
121 }
122
123 if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDOUTPATH))
124 dupstdout = false;
125
126 if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDERRORPATH))
127 dupstderr = false;
128
129 if (!w)
130 signal(SIGCHLD, SIG_IGN);
131
132 for (;;) {
133 if ((r = kevent(kq, NULL, 0, &kev, 1, &timeout)) == -1) {
134 syslog(LOG_DEBUG, "kevent(): %m");
135 goto out;
136 } else if (r == 0) {
137 ec = EXIT_SUCCESS;
138 goto out;
139 }
140
141 if (w) {
ddbbfbc1 142 dup2((int)kev.ident, STDIN_FILENO);
e91b9f68 143 if (dupstdout)
ddbbfbc1 144 dup2((int)kev.ident, STDOUT_FILENO);
e91b9f68 145 if (dupstderr)
ddbbfbc1 146 dup2((int)kev.ident, STDERR_FILENO);
e91b9f68
A
147 execv(prog, argv + 1);
148 syslog(LOG_ERR, "execv(): %m");
149 exit(EXIT_FAILURE);
150 }
151
ddbbfbc1 152 if ((r = accept((int)kev.ident, (struct sockaddr *)&ss, &slen)) == -1) {
e91b9f68
A
153 if (errno == EWOULDBLOCK)
154 continue;
ddbbfbc1 155 syslog(LOG_WARNING, "accept(): %m");
e91b9f68
A
156 goto out;
157 } else {
ddbbfbc1
A
158 if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
159 char fromhost[NI_MAXHOST];
160 char fromport[NI_MAXSERV];
161 int gni_r;
162
163 gni_r = getnameinfo((struct sockaddr *)&ss, slen,
164 fromhost, (socklen_t) sizeof fromhost,
165 fromport, (socklen_t) sizeof fromport,
166 NI_NUMERICHOST | NI_NUMERICSERV);
167
168 if (gni_r) {
169 syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r));
170 } else {
171 syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport);
172 }
e91b9f68 173 } else {
ddbbfbc1 174 syslog(LOG_WARNING, "%s: getnameinfo() only supports IPv4/IPv6. Connection from address family: %u", prog, ss.ss_family);
e91b9f68
A
175 }
176
177 switch (fork()) {
178 case -1:
179 syslog(LOG_WARNING, "fork(): %m");
dcace88f 180 if (errno != ENOMEM) {
ddbbfbc1
A
181 continue;
182 }
e91b9f68
A
183 goto out;
184 case 0:
185 break;
186 default:
187 close(r);
188 continue;
189 }
190
5b0a4722
A
191 setpgid(0, 0);
192
dcace88f 193#if !TARGET_OS_EMBEDDED
e91b9f68 194 if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) {
dcace88f
A
195 auditinfo_addr_t auinfo = {
196 .ai_termid = { .at_type = AU_IPv4 },
197 .ai_asid = AU_ASSIGN_ASID,
198 .ai_auid = getuid(),
199 .ai_flags = 0,
200 };
201 if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
202 char session[16];
203 snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
204 setenv("SECURITYSESSIONID", session, 1);
e91b9f68 205 } else {
dcace88f 206 syslog(LOG_NOTICE, "%s: Setting Audit Session ID failed: %d", prog, errno);
e91b9f68
A
207 }
208 }
5c88273d 209#endif // !TARGET_OS_EMBEDDED
ed34e3c3 210 fcntl(r, F_SETFL, 0);
fe044cc9 211 fcntl(r, F_SETFD, 1);
ed34e3c3 212 dup2(r, STDIN_FILENO);
e91b9f68 213 if (dupstdout)
ed34e3c3 214 dup2(r, STDOUT_FILENO);
e91b9f68 215 if (dupstderr)
ed34e3c3 216 dup2(r, STDERR_FILENO);
e91b9f68
A
217 signal(SIGCHLD, SIG_DFL);
218 execv(prog, argv + 1);
219 syslog(LOG_ERR, "execv(): %m");
ed34e3c3 220 exit(EXIT_FAILURE);
e91b9f68
A
221 }
222 }
223
224out:
225 exit(ec);
226}