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