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