]> git.saurik.com Git - apple/launchd.git/blob - launchd/src/launchproxy.c
481c8eb6149d63a36b462fd9822782f86852c797
[apple/launchd.git] / launchd / src / launchproxy.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <Security/Authorization.h>
24 #include <Security/AuthorizationTags.h>
25 #include <Security/AuthSession.h>
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
46 static int kq = 0;
47
48 static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused)))
49 {
50 struct kevent kev;
51 size_t i;
52 int fd;
53
54 switch (launch_data_get_type(o)) {
55 case LAUNCH_DATA_FD:
56 fd = launch_data_get_fd(o);
57 if (-1 == fd)
58 break;
59 fcntl(fd, F_SETFD, 1);
60 EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
61 if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1)
62 syslog(LOG_DEBUG, "kevent(%d): %m", fd);
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 }
74 }
75
76 int main(int argc __attribute__((unused)), char *argv[])
77 {
78 struct timespec timeout = { 10, 0 };
79 struct sockaddr_storage ss;
80 socklen_t slen = sizeof(ss);
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)
110 timeout.tv_sec = launch_data_get_integer(tmp);
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) {
142 dup2(kev.ident, STDIN_FILENO);
143 if (dupstdout)
144 dup2(kev.ident, STDOUT_FILENO);
145 if (dupstderr)
146 dup2(kev.ident, STDERR_FILENO);
147 execv(prog, argv + 1);
148 syslog(LOG_ERR, "execv(): %m");
149 exit(EXIT_FAILURE);
150 }
151
152 if ((r = accept(kev.ident, (struct sockaddr *)&ss, &slen)) == -1) {
153 if (errno == EWOULDBLOCK)
154 continue;
155 syslog(LOG_DEBUG, "accept(): %m");
156 goto out;
157 } else {
158 char fromhost[NI_MAXHOST];
159 char fromport[NI_MAXSERV];
160 int gni_r;
161
162 gni_r = getnameinfo((struct sockaddr *)&ss, slen,
163 fromhost, sizeof(fromhost),
164 fromport, sizeof(fromport),
165 NI_NUMERICHOST | NI_NUMERICSERV);
166
167 if (gni_r) {
168 syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r));
169 } else {
170 syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport);
171 }
172
173 switch (fork()) {
174 case -1:
175 syslog(LOG_WARNING, "fork(): %m");
176 goto out;
177 case 0:
178 break;
179 default:
180 close(r);
181 continue;
182 }
183
184 if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) {
185 if (SessionCreate) {
186 OSStatus scr = SessionCreate(0, 0);
187 if (scr != noErr)
188 syslog(LOG_NOTICE, "%s: SessionCreate() failed: %d", prog, scr);
189 } else {
190 syslog(LOG_NOTICE, "%s: SessionCreate == NULL!", prog);
191 }
192 }
193 fcntl(r, F_SETFL, 0);
194 dup2(r, STDIN_FILENO);
195 if (dupstdout)
196 dup2(r, STDOUT_FILENO);
197 if (dupstderr)
198 dup2(r, STDERR_FILENO);
199 signal(SIGCHLD, SIG_DFL);
200 execv(prog, argv + 1);
201 syslog(LOG_ERR, "execv(): %m");
202 exit(EXIT_FAILURE);
203 }
204 }
205
206 out:
207 exit(ec);
208 }