]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc.cc
Fix silent SSL/TLS failure on split-stack operating systems
[thirdparty/squid.git] / src / ipc.cc
CommitLineData
b13bbe1c 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
b13bbe1c 7 */
8
bbc27441
AJ
9/* DEBUG: section 54 Interprocess Communication */
10
582c2af2 11#include "squid.h"
f9b72e0c 12#include "comm/Connection.h"
c4ad1349 13#include "fd.h"
528b2c61 14#include "fde.h"
582c2af2 15#include "globals.h"
96d89ea0 16#include "ip/Address.h"
ed1a1519 17#include "ipc/Kid.h"
602d9612 18#include "rfc1738.h"
4d5904f7 19#include "SquidConfig.h"
96097880 20#include "SquidIpc.h"
561076e2 21#include "tools.h"
b13bbe1c 22
23static const char *hello_string = "hi there\n";
9ad18ba8 24#ifndef HELLO_BUF_SZ
b13bbe1c 25#define HELLO_BUF_SZ 32
9ad18ba8 26#endif
b13bbe1c 27static char hello_buf[HELLO_BUF_SZ];
28
29static int
30ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
31{
32 if (prfd >= 0)
62e76326 33 comm_close(prfd);
34
b13bbe1c 35 if (prfd != pwfd)
62e76326 36 if (pwfd >= 0)
37 comm_close(pwfd);
38
b13bbe1c 39 if (crfd >= 0)
62e76326 40 comm_close(crfd);
41
b13bbe1c 42 if (crfd != cwfd)
62e76326 43 if (cwfd >= 0)
44 comm_close(cwfd);
45
b13bbe1c 46 return -1;
47}
48
2e4528cc 49static void
50PutEnvironment()
51{
62e76326 52#if HAVE_PUTENV
2e4528cc 53 char *env_str;
54 int tmp_s;
62493678
AJ
55 env_str = (char *)xcalloc((tmp_s = strlen(Debug::debugOptions) + 32), 1);
56 snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Debug::debugOptions);
2e4528cc 57 putenv(env_str);
58#endif
59}
60
812dc4b8 61pid_t
b7ac5457 62ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
b13bbe1c 63{
64 pid_t pid;
b7ac5457
AJ
65 Ip::Address ChS;
66 Ip::Address PaS;
cc192b50 67 struct addrinfo *AI = NULL;
b13bbe1c 68 int crfd = -1;
69 int prfd = -1;
70 int cwfd = -1;
71 int pwfd = -1;
72 int fd;
86ed3fd2 73 int t1, t2, t3;
b13bbe1c 74 int x;
75
8a09e810 76#if USE_POLL && _SQUID_OSF_
91ef94d6 77 assert(type != IPC_FIFO);
78#endif
79
b13bbe1c 80 if (rfd)
62e76326 81 *rfd = -1;
82
b13bbe1c 83 if (wfd)
62e76326 84 *wfd = -1;
85
812dc4b8 86 if (hIpc)
87 *hIpc = NULL;
88
23d23d7a 89// NP: no wrapping around d and c usage since we *want* code expansion
148feb19
AJ
90#define IPC_CHECK_FAIL(f,d,c) \
91 if ((f) < 0) { \
92 debugs(54, DBG_CRITICAL, "ERROR: Failed to create helper " d " FD: " << c); \
93 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); \
94 } else void(0)
95
b13bbe1c 96 if (type == IPC_TCP_SOCKET) {
62e76326 97 crfd = cwfd = comm_open(SOCK_STREAM,
98 0,
99 local_addr,
62e76326 100 COMM_NOCLOEXEC,
101 name);
102 prfd = pwfd = comm_open(SOCK_STREAM,
f53969cc 103 0, /* protocol */
62e76326 104 local_addr,
f53969cc 105 0, /* blocking */
62e76326 106 name);
148feb19
AJ
107 IPC_CHECK_FAIL(crfd, "child read", "TCP " << local_addr);
108 IPC_CHECK_FAIL(prfd, "parent read", "TCP " << local_addr);
b13bbe1c 109 } else if (type == IPC_UDP_SOCKET) {
62e76326 110 crfd = cwfd = comm_open(SOCK_DGRAM,
111 0,
112 local_addr,
62e76326 113 COMM_NOCLOEXEC,
114 name);
115 prfd = pwfd = comm_open(SOCK_DGRAM,
116 0,
117 local_addr,
118 0,
62e76326 119 name);
148feb19
AJ
120 IPC_CHECK_FAIL(crfd, "child read", "UDP" << local_addr);
121 IPC_CHECK_FAIL(prfd, "parent read", "UDP" << local_addr);
b13bbe1c 122 } else if (type == IPC_FIFO) {
62e76326 123 int p2c[2];
124 int c2p[2];
125
126 if (pipe(p2c) < 0) {
fa84c01d 127 debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerror());
bd116068 128 return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
62e76326 129 }
bd116068
AJ
130 fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
131 fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
62e76326 132
133 if (pipe(c2p) < 0) {
fa84c01d 134 debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerror());
bd116068 135 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
62e76326 136 }
9708d22b 137 fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
138 fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
bd116068 139
148feb19
AJ
140 IPC_CHECK_FAIL(crfd, "child read", "FIFO pipe");
141 IPC_CHECK_FAIL(prfd, "parent read", "FIFO pipe");
142
1ccc0d40 143#if HAVE_SOCKETPAIR && defined(AF_UNIX)
62e76326 144
1ccc0d40 145 } else if (type == IPC_UNIX_STREAM) {
62e76326 146 int fds[2];
147 int buflen = 32768;
148
149 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
fa84c01d 150 debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerror());
62e76326 151 return -1;
152 }
153
154 setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
155 setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
156 setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
157 setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
9708d22b 158 fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent");
159 fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX STREAM Parent");
148feb19
AJ
160 IPC_CHECK_FAIL(crfd, "child read", "UDS socket");
161 IPC_CHECK_FAIL(prfd, "parent read", "UDS socket");
162
1ccc0d40 163 } else if (type == IPC_UNIX_DGRAM) {
62e76326 164 int fds[2];
165
166 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
fa84c01d 167 debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerror());
62e76326 168 return -1;
169 }
170
9708d22b 171 fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent");
172 fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent");
148feb19
AJ
173
174 IPC_CHECK_FAIL(crfd, "child read", "UDS datagram");
175 IPC_CHECK_FAIL(prfd, "parent read", "UDS datagram");
1ccc0d40 176#endif
62e76326 177
b13bbe1c 178 } else {
62e76326 179 assert(IPC_NONE);
b13bbe1c 180 }
62e76326 181
bf8fe701 182 debugs(54, 3, "ipcCreate: prfd FD " << prfd);
183 debugs(54, 3, "ipcCreate: pwfd FD " << pwfd);
184 debugs(54, 3, "ipcCreate: crfd FD " << crfd);
185 debugs(54, 3, "ipcCreate: cwfd FD " << cwfd);
b13bbe1c 186
b13bbe1c 187 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
851614a8 188 Ip::Address::InitAddr(AI);
62e76326 189
cc192b50 190 if (getsockname(pwfd, AI->ai_addr, &AI->ai_addrlen) < 0) {
851614a8 191 Ip::Address::FreeAddr(AI);
fa84c01d 192 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
62e76326 193 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
194 }
195
cc192b50 196 PaS = *AI;
bf8fe701 197
cc192b50 198 debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << PaS);
62e76326 199
851614a8 200 Ip::Address::FreeAddr(AI);
cc192b50 201
851614a8 202 Ip::Address::InitAddr(AI);
cc192b50 203
204 if (getsockname(crfd, AI->ai_addr, &AI->ai_addrlen) < 0) {
851614a8 205 Ip::Address::FreeAddr(AI);
fa84c01d 206 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
62e76326 207 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
208 }
209
cc192b50 210 ChS = *AI;
211
851614a8 212 Ip::Address::FreeAddr(AI);
cc192b50 213
214 debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << ChS );
bf8fe701 215
b13bbe1c 216 }
62e76326 217
b13bbe1c 218 if (type == IPC_TCP_SOCKET) {
62e76326 219 if (listen(crfd, 1) < 0) {
e0236918 220 debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerror());
62e76326 221 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
222 }
223
bf8fe701 224 debugs(54, 3, "ipcCreate: FD " << crfd << " listening...");
b13bbe1c 225 }
62e76326 226
b13bbe1c 227 /* flush or else we get dup data if unbuffered_logs is set */
228 logsFlush();
62e76326 229
b13bbe1c 230 if ((pid = fork()) < 0) {
e0236918 231 debugs(54, DBG_IMPORTANT, "ipcCreate: fork: " << xstrerror());
62e76326 232 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
b13bbe1c 233 }
62e76326 234
f53969cc 235 if (pid > 0) { /* parent */
62e76326 236 /* close shared socket with child */
237 comm_close(crfd);
238
239 if (cwfd != crfd)
240 comm_close(cwfd);
241
242 cwfd = crfd = -1;
243
244 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
4ee57cbe 245 if (comm_connect_addr(pwfd, ChS) == Comm::COMM_ERROR)
62e76326 246 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
247 }
248
62e76326 249 if (type == IPC_UDP_SOCKET)
9ad18ba8 250 x = comm_udp_recv(prfd, hello_buf, sizeof(hello_buf)-1, 0);
62e76326 251 else
9ad18ba8
AJ
252 x = read(prfd, hello_buf, sizeof(hello_buf)-1);
253 if (x >= 0)
254 hello_buf[x+1] = '\0';
62e76326 255
256 if (x < 0) {
fa84c01d
FC
257 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
258 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
62e76326 259 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
260 } else if (strcmp(hello_buf, hello_string)) {
fa84c01d
FC
261 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
262 debugs(54, DBG_CRITICAL, "--> read returned " << x);
263 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
62e76326 264 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
265 }
266
933dd095 267 commUnsetFdTimeout(prfd);
62e76326 268 commSetNonBlocking(prfd);
269 commSetNonBlocking(pwfd);
270
271 if (rfd)
272 *rfd = prfd;
273
274 if (wfd)
275 *wfd = pwfd;
276
277 fd_table[prfd].flags.ipc = 1;
278
279 fd_table[pwfd].flags.ipc = 1;
280
281 if (Config.sleep_after_fork) {
282 /* XXX emulation of usleep() */
283
284 struct timeval sl;
285 sl.tv_sec = Config.sleep_after_fork / 1000000;
286 sl.tv_usec = Config.sleep_after_fork % 1000000;
287 select(0, NULL, NULL, NULL, &sl);
288 }
289
290 return pid;
b13bbe1c 291 }
62e76326 292
b13bbe1c 293 /* child */
ed1a1519 294 TheProcessKind = pkHelper;
f53969cc 295 no_suid(); /* give up extra priviliges */
62e76326 296
b13bbe1c 297 /* close shared socket with parent */
2dde67ef 298 close(prfd);
62e76326 299
b13bbe1c 300 if (pwfd != prfd)
62e76326 301 close(pwfd);
302
b13bbe1c 303 pwfd = prfd = -1;
304
305 if (type == IPC_TCP_SOCKET) {
bf8fe701 306 debugs(54, 3, "ipcCreate: calling accept on FD " << crfd);
62e76326 307
308 if ((fd = accept(crfd, NULL, NULL)) < 0) {
fa84c01d 309 debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerror());
62e76326 310 _exit(1);
311 }
312
bf8fe701 313 debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd);
62e76326 314 close(crfd);
315 cwfd = crfd = fd;
b13bbe1c 316 } else if (type == IPC_UDP_SOCKET) {
4ee57cbe 317 if (comm_connect_addr(crfd, PaS) == Comm::COMM_ERROR)
62e76326 318 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
b13bbe1c 319 }
62e76326 320
b13bbe1c 321 if (type == IPC_UDP_SOCKET) {
62e76326 322 x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0);
323
324 if (x < 0) {
fa84c01d
FC
325 debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror());
326 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
62e76326 327 _exit(1);
328 }
b13bbe1c 329 } else {
62e76326 330 if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) {
fa84c01d
FC
331 debugs(54, DBG_CRITICAL, "write FD " << cwfd << ": " << xstrerror());
332 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
62e76326 333 _exit(1);
334 }
b13bbe1c 335 }
62e76326 336
2e4528cc 337 PutEnvironment();
b13bbe1c 338 /*
26ac0430 339 * This double-dup stuff avoids problems when one of
86ed3fd2 340 * crfd, cwfd, or debug_log are in the rage 0-2.
b13bbe1c 341 */
62e76326 342
86ed3fd2 343 do {
bed704f7 344 /* First make sure 0-2 is occupied by something. Gets cleaned up later */
345 x = dup(crfd);
346 assert(x > -1);
347 } while (x < 3 && x > -1);
62e76326 348
bed704f7 349 close(x);
62e76326 350
86ed3fd2 351 t1 = dup(crfd);
62e76326 352
86ed3fd2 353 t2 = dup(cwfd);
62e76326 354
86ed3fd2 355 t3 = dup(fileno(debug_log));
62e76326 356
86ed3fd2 357 assert(t1 > 2 && t2 > 2 && t3 > 2);
62e76326 358
86ed3fd2 359 close(crfd);
62e76326 360
86ed3fd2 361 close(cwfd);
62e76326 362
86ed3fd2 363 close(fileno(debug_log));
62e76326 364
86ed3fd2 365 dup2(t1, 0);
62e76326 366
86ed3fd2 367 dup2(t2, 1);
62e76326 368
86ed3fd2 369 dup2(t3, 2);
62e76326 370
86ed3fd2 371 close(t1);
62e76326 372
86ed3fd2 373 close(t2);
62e76326 374
86ed3fd2 375 close(t3);
62e76326 376
3cdb7cd0 377 /* Make sure all other filedescriptors are closed */
95dc7ff4 378 for (x = 3; x < SQUID_MAXFD; ++x)
62e76326 379 close(x);
380
62740359 381#if HAVE_SETSID
26e75de2 382 if (opt_no_daemon)
af6a12ee 383 setsid();
62740359 384#endif
385
a2c963ae 386 execvp(prog, (char *const *) args);
62e76326 387
3cdb7cd0 388 debug_log = fdopen(2, "a+");
62e76326 389
fa84c01d 390 debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": " << xstrerror());
62e76326 391
b13bbe1c 392 _exit(1);
62e76326 393
b13bbe1c 394 return 0;
395}
f53969cc 396