Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/openlaunchd
Path: blob/master/launchproxy/launchproxy.c
374 views
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 "config.h"
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
39
#if !TARGET_OS_EMBEDDED
40
#include <bsm/audit.h>
41
#if __APPLE__
42
/*
43
* None of the functions or enums declared in bsm/audit_session.h are used in
44
* launchproxy. It does not in fact exist in any shape inside of OpenBSM <http://www.trustedbsd.org/openbsm.html>
45
*
46
* <https://gist.github.com/philips/6880b6bfbcb33c3b3653>
47
*/
48
#include <bsm/audit_session.h>
49
#endif
50
#endif // !TARGET_OS_EMBEDDED
51
52
#include "launch.h"
53
54
#ifndef __APPLE__
55
/*
56
* Since launchd is core to Apple operating systems, they've got a
57
* system-specified syslog(3) facility defined *just* for launchd. Non-Apple
58
* OSes lack this system defined facility, but have local use facilities
59
* available
60
*/
61
#define LOG_LAUNCHD (23<<3)
62
#endif
63
64
static int kq = 0;
65
66
static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused)))
67
{
68
struct kevent kev;
69
size_t i;
70
int fd;
71
72
switch (launch_data_get_type(o)) {
73
case LAUNCH_DATA_FD:
74
fd = launch_data_get_fd(o);
75
if (-1 == fd)
76
break;
77
fcntl(fd, F_SETFD, 1);
78
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
79
if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1)
80
syslog(LOG_DEBUG, "kevent(%d): %m", fd);
81
break;
82
case LAUNCH_DATA_ARRAY:
83
for (i = 0; i < launch_data_array_get_count(o); i++)
84
find_fds(launch_data_array_get_index(o, i), NULL, NULL);
85
break;
86
case LAUNCH_DATA_DICTIONARY:
87
launch_data_dict_iterate(o, find_fds, NULL);
88
break;
89
default:
90
break;
91
}
92
}
93
94
int main(int argc __attribute__((unused)), char *argv[])
95
{
96
struct timespec timeout = { 10, 0 };
97
struct sockaddr_storage ss;
98
socklen_t slen = (socklen_t)sizeof ss;
99
struct kevent kev;
100
int r, ec = EXIT_FAILURE;
101
launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
102
const char *prog = argv[1];
103
bool w = false, dupstdout = true, dupstderr = true;
104
105
launch_data_set_string(msg, LAUNCH_KEY_CHECKIN);
106
107
openlog(getprogname(), LOG_PERROR|LOG_PID|LOG_CONS, LOG_LAUNCHD);
108
109
kq = kqueue();
110
111
if ((resp = launch_msg(msg)) == NULL) {
112
syslog(LOG_ERR, "launch_msg(%s): %m", LAUNCH_KEY_CHECKIN);
113
goto out;
114
}
115
116
launch_data_free(msg);
117
118
tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
119
if (tmp) {
120
find_fds(tmp, NULL, NULL);
121
} else {
122
syslog(LOG_ERR, "No FDs found to answer requests on!");
123
goto out;
124
}
125
126
tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT);
127
if (tmp)
128
timeout.tv_sec = (int)launch_data_get_integer(tmp);
129
130
tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_PROGRAM);
131
if (tmp)
132
prog = launch_data_get_string(tmp);
133
134
tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_INETDCOMPATIBILITY);
135
if (tmp) {
136
tmp = launch_data_dict_lookup(tmp, LAUNCH_JOBINETDCOMPATIBILITY_WAIT);
137
if (tmp)
138
w = launch_data_get_bool(tmp);
139
}
140
141
if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDOUTPATH))
142
dupstdout = false;
143
144
if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDERRORPATH))
145
dupstderr = false;
146
147
if (!w)
148
signal(SIGCHLD, SIG_IGN);
149
150
for (;;) {
151
if ((r = kevent(kq, NULL, 0, &kev, 1, &timeout)) == -1) {
152
syslog(LOG_DEBUG, "kevent(): %m");
153
goto out;
154
} else if (r == 0) {
155
ec = EXIT_SUCCESS;
156
goto out;
157
}
158
159
if (w) {
160
dup2((int)kev.ident, STDIN_FILENO);
161
if (dupstdout)
162
dup2((int)kev.ident, STDOUT_FILENO);
163
if (dupstderr)
164
dup2((int)kev.ident, STDERR_FILENO);
165
execv(prog, argv + 1);
166
syslog(LOG_ERR, "execv(): %m");
167
exit(EXIT_FAILURE);
168
}
169
170
if ((r = accept((int)kev.ident, (struct sockaddr *)&ss, &slen)) == -1) {
171
if (errno == EWOULDBLOCK)
172
continue;
173
syslog(LOG_WARNING, "accept(): %m");
174
goto out;
175
} else {
176
if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
177
char fromhost[NI_MAXHOST];
178
char fromport[NI_MAXSERV];
179
int gni_r;
180
181
gni_r = getnameinfo((struct sockaddr *)&ss, slen,
182
fromhost, (socklen_t) sizeof fromhost,
183
fromport, (socklen_t) sizeof fromport,
184
NI_NUMERICHOST | NI_NUMERICSERV);
185
186
if (gni_r) {
187
syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r));
188
} else {
189
syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport);
190
}
191
} else {
192
syslog(LOG_WARNING, "%s: getnameinfo() only supports IPv4/IPv6. Connection from address family: %u", prog, ss.ss_family);
193
}
194
195
switch (fork()) {
196
case -1:
197
syslog(LOG_WARNING, "fork(): %m");
198
if (errno != ENOMEM) {
199
continue;
200
}
201
goto out;
202
case 0:
203
break;
204
default:
205
close(r);
206
continue;
207
}
208
209
setpgid(0, 0);
210
211
#if !TARGET_OS_EMBEDDED
212
if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) {
213
auditinfo_addr_t auinfo = {
214
.ai_termid = { .at_type = AU_IPv4 },
215
.ai_asid = AU_ASSIGN_ASID,
216
.ai_auid = getuid(),
217
.ai_flags = 0,
218
};
219
if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
220
char session[16];
221
snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
222
setenv("SECURITYSESSIONID", session, 1);
223
} else {
224
syslog(LOG_NOTICE, "%s: Setting Audit Session ID failed: %d", prog, errno);
225
}
226
}
227
#endif // !TARGET_OS_EMBEDDED
228
fcntl(r, F_SETFL, 0);
229
fcntl(r, F_SETFD, 1);
230
dup2(r, STDIN_FILENO);
231
if (dupstdout)
232
dup2(r, STDOUT_FILENO);
233
if (dupstderr)
234
dup2(r, STDERR_FILENO);
235
signal(SIGCHLD, SIG_DFL);
236
execv(prog, argv + 1);
237
syslog(LOG_ERR, "execv(): %m");
238
exit(EXIT_FAILURE);
239
}
240
}
241
242
out:
243
exit(ec);
244
}
245
246