]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Bug 5428: Warn if pkg-config is not found (#1902)
[thirdparty/squid.git] / src / tools.cc
CommitLineData
30a4f2a8 1/*
b8ae064d 2 * Copyright (C) 1996-2023 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.
019dd986 7 */
44a47c6e 8
bbc27441
AJ
9/* DEBUG: section 21 Misc Functions */
10
582c2af2 11#include "squid.h"
602d9612 12#include "anyp/PortCfg.h"
e0d28505 13#include "base/Subscription.h"
93da1f99 14#include "client_side.h"
2745fea5 15#include "fatal.h"
528b2c61 16#include "fde.h"
95e6d864 17#include "fqdncache.h"
b3f7fd88 18#include "fs_io.h"
65d448bc 19#include "htcp.h"
d3dddfb5 20#include "http/Stream.h"
e0d28505 21#include "ICP.h"
96d89ea0 22#include "ip/Intercept.h"
425de4c8 23#include "ip/QosConfig.h"
602d9612
A
24#include "ipc/Coordinator.h"
25#include "ipc/Kids.h"
26#include "ipcache.h"
0eb49b6d 27#include "MemBuf.h"
e99fa721 28#include "sbuf/Stream.h"
4d5904f7 29#include "SquidConfig.h"
a98bcbee 30#include "SquidMath.h"
2745fea5 31#include "store/Disks.h"
602d9612 32#include "tools.h"
27bc2077 33#include "wordlist.h"
44a47c6e 34
1a30fdf5 35#include <cerrno>
59eac907
AJ
36#if HAVE_SYS_CAPABILITY_H
37#include <sys/capability.h>
38#endif
62ae0622 39#if HAVE_SYS_PRCTL_H
40#include <sys/prctl.h>
41#endif
321223fe
DC
42#if HAVE_SYS_PROCCTL_H
43#include <sys/procctl.h>
44#endif
45#if HAVE_PRIV_H
46#include <priv.h>
47#endif
a186e0d9 48#if HAVE_PSAPI_H
e30fe60a
AJ
49#include <psapi.h>
50#endif
582c2af2
FC
51#if HAVE_SYS_STAT_H
52#include <sys/stat.h>
53#endif
54#if HAVE_SYS_WAIT_H
55#include <sys/wait.h>
56#endif
57#if HAVE_GRP_H
58#include <grp.h>
59#endif
62ae0622 60
090089c4 61#define DEAD_MSG "\
c5c666ab 62The Squid Cache (version %s) died.\n\
090089c4 63\n\
c5c666ab 64You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 65If a core file was created (possibly in the swap directory),\n\
b8de7ebe 66please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
8311b837 67and report the trace back to squid-bugs@lists.squid-cache.org.\n\
090089c4 68\n\
69Thanks!\n"
70
f5b8bbc4 71static void mail_warranty(void);
ff2afd7f 72static void restoreCapabilities(bool keep);
a2c48c98 73int DebugSignal = -1;
8b505ba9 74SBuf service_name(APP_SHORTNAME);
24382924 75
1191b93b 76#if _SQUID_LINUX_
941a3077 77/* Workaround for crappy glic header files */
e6ccf245 78SQUIDCEXTERN int backtrace(void *, int);
79SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
80SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
10da753f
FC
81#else /* _SQUID_LINUX_ */
82/* needed on Opensolaris for backtrace_symbols_fd */
83#if HAVE_EXECINFO_H
84#include <execinfo.h>
85#endif /* HAVE_EXECINFO_H */
86
941a3077 87#endif /* _SQUID_LINUX */
88
5d821589
AJ
89static char tmp_error_buf[32768]; /* 32KB */
90
4a5a6c62 91void
429fdbec 92releaseServerSockets(void)
93{
65d448bc 94 // Release the main ports as early as possible
62e76326 95
e7ce227f 96 // clear http_port, https_port, and ftp_port lists
434a79b0 97 clientConnectionsClose();
62e76326 98
e0d28505 99 // clear icp_port's
65d448bc 100 icpClosePorts();
62e76326 101
e0d28505 102 // XXX: Why not the HTCP, SNMP, DNS ports as well?
65d448bc 103 // XXX: why does this differ from main closeServerConnections() anyway ?
429fdbec 104}
105
b8d8561b 106static char *
0673c0ba 107dead_msg(void)
090089c4 108{
95d659f0 109 LOCAL_ARRAY(char, msg, 1024);
56878878 110 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 111 return msg;
112}
113
24382924 114static void
0673c0ba 115mail_warranty(void)
090089c4 116{
aee3523a 117 FILE *fp = nullptr;
6e40f263 118 static char command[256];
50536c47 119
a2c13db1
AJ
120 /*
121 * NP: umask() takes the mask of bits we DONT want set.
122 *
123 * We want the current user to have read/write access
124 * and since this file will be passed to mailsystem,
125 * the group and other must have read access.
126 */
127 const mode_t prev_umask=umask(S_IXUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH);
62e76326 128
50536c47 129#if HAVE_MKSTEMP
b99a6dec 130 char filename[] = "/tmp/squid-XXXXXX";
131 int tfd = mkstemp(filename);
aee3523a 132 if (tfd < 0 || (fp = fdopen(tfd, "w")) == nullptr) {
50536c47 133 umask(prev_umask);
62e76326 134 return;
50536c47 135 }
b99a6dec 136#else
137 char *filename;
50536c47
FC
138 // XXX tempnam is obsolete since POSIX.2008-1
139 // tmpfile is not an option, we want the created files to stick around
a1b1756c 140 if ((filename = tempnam(nullptr, APP_SHORTNAME)) == NULL ||
6a1a5b78 141 (fp = fopen(filename, "w")) == NULL) {
50536c47 142 umask(prev_umask);
62e76326 143 return;
50536c47 144 }
b99a6dec 145#endif
50536c47 146 umask(prev_umask);
62e76326 147
abacf776 148 if (Config.EmailFrom)
149 fprintf(fp, "From: %s\n", Config.EmailFrom);
150 else
7dbca7a4 151 fprintf(fp, "From: %s@%s\n", APP_SHORTNAME, uniqueHostname());
62e76326 152
edae7bc0 153 fprintf(fp, "To: %s\n", Config.adminEmail);
6e40f263 154 fprintf(fp, "Subject: %s\n", dead_msg());
155 fclose(fp);
62e76326 156
d084bf20 157 snprintf(command, 256, "%s %s < %s", Config.EmailProgram, Config.adminEmail, filename);
f53969cc 158 if (system(command)) {} /* XXX should avoid system(3) */
6e40f263 159 unlink(filename);
87cedd31
AJ
160#if !HAVE_MKSTEMP
161 xfree(filename); // tempnam() requires us to free its allocation
162#endif
090089c4 163}
164
4a5a6c62 165void
43c3424b 166dumpMallocStats(void)
3f43b19b 167{
88738790 168#if HAVE_MSTATS && HAVE_GNUMALLOC_H
62e76326 169
88738790 170 struct mstats ms = mstats();
016c612a 171 fprintf(DebugStream(), "\ttotal space in arena: %6d KB\n",
62e76326 172 (int) (ms.bytes_total >> 10));
016c612a 173 fprintf(DebugStream(), "\tTotal free: %6d KB %d%%\n",
62e76326 174 (int) (ms.bytes_free >> 10),
a98bcbee 175 Math::intPercent(ms.bytes_free, ms.bytes_total));
4572073a 176#endif
3f43b19b 177}
30a4f2a8 178
f2908497 179void
180squid_getrusage(struct rusage *r)
f0f81709 181{
8da94b66 182 memset(r, '\0', sizeof(struct rusage));
a186e0d9 183#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
1da023b5 184#if _SQUID_SOLARIS_
cd19f0b6 185 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
186 enter_suid();
187#endif
62e76326 188
f2908497 189 getrusage(RUSAGE_SELF, r);
62e76326 190
e30fe60a 191#if _SQUID_SOLARIS_
cd19f0b6 192 leave_suid();
193#endif
e30fe60a 194
a186e0d9 195#elif defined(PSAPI_VERSION)
e30fe60a
AJ
196 // Windows has an alternative method if there is no POSIX getrusage defined.
197 if (WIN32_OS_version >= _WIN_OS_WINNT) {
198 /* On Windows NT and later call PSAPI.DLL for process Memory */
2f8abb64 199 /* information -- Guido Serassio */
e30fe60a
AJ
200 HANDLE hProcess;
201 PROCESS_MEMORY_COUNTERS pmc;
202 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
203 PROCESS_VM_READ,
204 FALSE, GetCurrentProcessId());
205 {
206 /* Microsoft CRT doesn't have getrusage function, */
207 /* so we get process CPU time information from PSAPI.DLL. */
208 FILETIME ftCreate, ftExit, ftKernel, ftUser;
209 if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
210 int64_t *ptUser = (int64_t *)&ftUser;
211 int64_t tUser64 = *ptUser / 10;
212 int64_t *ptKernel = (int64_t *)&ftKernel;
213 int64_t tKernel64 = *ptKernel / 10;
214 r->ru_utime.tv_sec =(long)(tUser64 / 1000000);
215 r->ru_stime.tv_sec =(long)(tKernel64 / 1000000);
216 r->ru_utime.tv_usec =(long)(tUser64 % 1000000);
217 r->ru_stime.tv_usec =(long)(tKernel64 % 1000000);
218 } else {
219 CloseHandle( hProcess );
220 return;
221 }
222 }
223 if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
224 r->ru_maxrss=(DWORD)(pmc.WorkingSetSize / getpagesize());
225 r->ru_majflt=pmc.PageFaultCount;
226 } else {
227 CloseHandle( hProcess );
228 return;
229 }
230
231 CloseHandle( hProcess );
232 }
56983a01 233#endif
f2908497 234}
235
236double
62e76326 237
f2908497 238rusage_cputime(struct rusage *r)
239{
240 return (double) r->ru_stime.tv_sec +
62e76326 241 (double) r->ru_utime.tv_sec +
242 (double) r->ru_stime.tv_usec / 1000000.0 +
243 (double) r->ru_utime.tv_usec / 1000000.0;
f2908497 244}
245
ec603b25 246/* Hack for some HP-UX preprocessors */
247#ifndef HAVE_GETPAGESIZE
248#define HAVE_GETPAGESIZE 0
249#endif
250
f2908497 251int
62e76326 252
f2908497 253rusage_maxrss(struct rusage *r)
254{
8a09e810 255#if _SQUID_SGI_ && _ABIAPI
4fdc3986 256 return r->ru_pad[0];
8a09e810 257#elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
62e76326 258
f2908497 259 return r->ru_maxrss;
6b8e7481 260#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
62e76326 261
f2908497 262 return (r->ru_maxrss * getpagesize()) >> 10;
c7a1083d 263#elif defined(PAGESIZE)
62e76326 264
c7a1083d 265 return (r->ru_maxrss * PAGESIZE) >> 10;
8505e57b 266#else
62e76326 267
8505e57b 268 return r->ru_maxrss;
f2908497 269#endif
270}
271
272int
62e76326 273
f2908497 274rusage_pagefaults(struct rusage *r)
275{
8a09e810 276#if _SQUID_SGI_ && _ABIAPI
4fdc3986 277 return r->ru_pad[5];
278#else
62e76326 279
f2908497 280 return r->ru_majflt;
4fdc3986 281#endif
f2908497 282}
283
321223fe
DC
284/// Make the process traceable if possible. Call setTraceability() instead!
285/// Traceable processes may support attachment via ptrace(2) or ktrace(2),
286/// debugging sysctls, hwpmc(4), dtrace(1) and core dumping.
287static void
288makeTraceable()
289{
290 const auto handleError = [](const char * const syscall, const int savedErrno) {
291 throw TextException(ToSBuf(syscall, " failure: ", xstrerr(savedErrno)), Here());
292 };
293#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
294 if (prctl(PR_SET_DUMPABLE, 1) != 0)
295 handleError("prctl(PR_SET_DUMPABLE)", errno);
296#elif HAVE_PROCCTL && defined(PROC_TRACE_CTL)
297 // TODO: when FreeBSD 14 becomes the lowest version, we can
298 // possibly save one getpid syscall, for now still necessary.
299 int traceable = PROC_TRACE_CTL_ENABLE;
300 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) != 0)
301 handleError("procctl(PROC_TRACE_CTL_ENABLE)", errno);
302#elif HAVE_SETPFLAGS
303 if (setpflags(__PROC_PROTECT, 0) != 0)
304 handleError("setpflags(__PROC_PROTECT)", errno);
305#else
306 debugs(50, 2, "WARNING: Assuming this process is traceable");
307 (void)handleError; // just "use" the variable; there is no error here
308#endif
309}
310
311/// Make the process traceable if necessary.
312/// \sa makeTraceable()
313static void
314setTraceability()
315{
316 // for now, setting coredump_dir is required to make the process traceable
317 if (!Config.coredump_dir)
318 return;
319
320 try {
321 makeTraceable();
322 } catch (...) {
323 debugs(50, DBG_IMPORTANT, "ERROR: Cannot make the process traceable:" <<
324 Debug::Extra << "exception: " << CurrentException);
325 }
326}
327
4a5a6c62 328void
f2908497 329PrintRusage(void)
330{
62e76326 331
f2908497 332 struct rusage rusage;
333 squid_getrusage(&rusage);
016c612a 334 fprintf(DebugStream(), "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
62e76326 335 rusage_cputime(&rusage),
336 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
337 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
016c612a 338 fprintf(DebugStream(), "Maximum Resident Size: %d KB\n",
62e76326 339 rusage_maxrss(&rusage));
016c612a 340 fprintf(DebugStream(), "Page faults with physical i/o: %d\n",
62e76326 341 rusage_pagefaults(&rusage));
f0f81709 342}
343
b8d8561b 344void
345death(int sig)
44a47c6e 346{
0e08ce4b 347 if (sig == SIGSEGV)
e863656d 348 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Segment Violation...dying.");
0e08ce4b 349 else if (sig == SIGBUS)
e863656d 350 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Bus Error...dying.");
0e08ce4b 351 else
e863656d 352 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received signal " << sig << "...dying.");
0b4639af 353
0a081cb0 354#if PRINT_STACK_TRACE
1191b93b 355#if _SQUID_HPUX_
0b4639af 356 {
f53969cc 357 extern void U_STACK_TRACE(void); /* link with -lcl */
016c612a
AJ
358 fflush(DebugStream());
359 dup2(fileno(DebugStream()), 2);
62e76326 360 U_STACK_TRACE();
0b4639af 361 }
62e76326 362
0b4639af 363#endif /* _SQUID_HPUX_ */
8a09e810 364#if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
f53969cc
SM
365 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
366 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
016c612a
AJ
367 fflush(DebugStream());
368 dup2(fileno(DebugStream()), fileno(stdout));
62e76326 369 opcom_stack_trace();
370 fflush(stdout);
0b4639af 371 }
62e76326 372
10da753f 373#endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
ce3d30fb 374#if HAVE_BACKTRACE_SYMBOLS_FD
375 {
b56b37cf 376 static void *callarray[8192];
62e76326 377 int n;
378 n = backtrace(callarray, 8192);
016c612a 379 backtrace_symbols_fd(callarray, n, fileno(DebugStream()));
ce3d30fb 380 }
62e76326 381
ce3d30fb 382#endif
0b4639af 383#endif /* PRINT_STACK_TRACE */
384
7aa9bb3e 385#if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
44a47c6e 386 signal(SIGSEGV, SIG_DFL);
62e76326 387
44a47c6e 388 signal(SIGBUS, SIG_DFL);
62e76326 389
0e08ce4b 390 signal(sig, SIG_DFL);
62e76326 391
30a4f2a8 392#endif
62e76326 393
429fdbec 394 releaseServerSockets();
62e76326 395
e3ef2b09 396 storeDirWriteCleanLogs(0);
62e76326 397
4b0f5de8 398 if (!shutting_down) {
399 PrintRusage();
62e76326 400
4b0f5de8 401 dumpMallocStats();
402 }
62e76326 403
6e40f263 404 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
62e76326 405 /* skip if more than 10 days old */
406
407 if (Config.adminEmail)
408 mail_warranty();
329ce686 409
410 puts(dead_msg());
6e40f263 411 }
62e76326 412
61be1d8e 413 Debug::PrepareToDie();
44a47c6e 414 abort();
415}
416
a2c48c98
AR
417void
418BroadcastSignalIfAny(int& sig)
419{
420 if (sig > 0) {
dbf55289
CT
421 if (IamMasterProcess()) {
422 for (int i = TheKids.count() - 1; i >= 0; --i) {
00e2479d
AR
423 const auto &kid = TheKids.get(i);
424 if (kid.running())
425 kill(kid.getPid(), sig);
dbf55289
CT
426 }
427 }
a2c48c98
AR
428 sig = -1;
429 }
430}
44a47c6e 431
b8d8561b 432void
23d92c64 433sigusr2_handle(int sig)
090089c4 434{
30a4f2a8 435 static int state = 0;
96e03dd8 436 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
62e76326 437
a2c48c98
AR
438 DebugSignal = sig;
439
30a4f2a8 440 if (state == 0) {
d7298d24 441 Debug::parseOptions("ALL,7");
62e76326 442 state = 1;
30a4f2a8 443 } else {
62493678 444 Debug::parseOptions(Debug::debugOptions);
62e76326 445 state = 0;
30a4f2a8 446 }
62e76326 447
30a4f2a8 448#if !HAVE_SIGACTION
b69e9ffa
AJ
449 /* reinstall */
450 if (signal(sig, sigusr2_handle) == SIG_ERR) {
451 int xerrno = errno;
452 debugs(50, DBG_CRITICAL, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerr(xerrno));
453 }
090089c4 454#endif
455}
456
b8d8561b 457void
af6a12ee
AJ
458debug_trap(const char *message)
459{
4a69c163 460 if (!opt_catch_signals)
62e76326 461 fatal_dump(message);
462
e863656d 463 debugs(50, DBG_CRITICAL, "WARNING: " << message);
85b701ed 464}
465
0ee4272b 466const char *
0673c0ba 467getMyHostname(void)
44a47c6e 468{
95d659f0 469 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 470 static int present = 0;
aee3523a 471 struct addrinfo *AI = nullptr;
b7ac5457 472 Ip::Address sa;
62e76326 473
aee3523a 474 if (Config.visibleHostname != nullptr)
62e76326 475 return Config.visibleHostname;
476
d20b1cd0 477 if (present)
62e76326 478 return host;
479
d20b1cd0 480 host[0] = '\0';
62e76326 481
aee3523a 482 if (HttpPortList != nullptr && sa.isAnyAddr())
fa720bfb 483 sa = HttpPortList->s;
62e76326 484
aa2b5399 485 /*
486 * If the first http_port address has a specific address, try a
487 * reverse DNS lookup on it.
488 */
4dd643d5 489 if ( !sa.isAnyAddr() ) {
62e76326 490
4dd643d5 491 sa.getAddrInfo(AI);
cc192b50 492 /* we are looking for a name. */
aee3523a 493 if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, nullptr, 0, NI_NAMEREQD ) == 0) {
62e76326 494 /* DNS lookup successful */
495 /* use the official name from DNS lookup */
cc192b50 496 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
bf8fe701 497
62e76326 498 present = 1;
499
851614a8 500 Ip::Address::FreeAddr(AI);
cc192b50 501
62e76326 502 if (strchr(host, '.'))
503 return host;
62e76326 504 }
505
851614a8 506 Ip::Address::FreeAddr(AI);
c19d1320
AJ
507 debugs(50, 2, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
508 }
509
510 // still no host. fallback to gethostname()
511 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
b69e9ffa
AJ
512 int xerrno = errno;
513 debugs(50, DBG_IMPORTANT, "WARNING: gethostname failed: " << xstrerr(xerrno));
26ac0430 514 } else {
c19d1320
AJ
515 /* Verify that the hostname given resolves properly */
516 struct addrinfo hints;
517 memset(&hints, 0, sizeof(addrinfo));
518 hints.ai_flags = AI_CANONNAME;
62e76326 519
aee3523a 520 if (getaddrinfo(host, nullptr, nullptr, &AI) == 0) {
c19d1320
AJ
521 /* DNS lookup successful */
522 /* use the official name from DNS lookup */
523 debugs(50, 6, "getMyHostname: '" << host << "' has DNS resolution.");
524 present = 1;
525
526 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
4dd643d5 527 if (AI)
c19d1320 528 freeaddrinfo(AI);
cc192b50 529
c19d1320 530 return host;
cc192b50 531 }
b69e9ffa 532 int xerrno = errno;
c19d1320 533
4dd643d5
AJ
534 if (AI)
535 freeaddrinfo(AI);
b69e9ffa 536 debugs(50, DBG_IMPORTANT, "WARNING: '" << host << "' rDNS test failed: " << xstrerr(xerrno));
44a47c6e 537 }
62e76326 538
c19d1320
AJ
539 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
540 debugs(50, DBG_CRITICAL, "WARNING: Could not determine this machines public hostname. " <<
541 "Please configure one or set 'visible_hostname'.");
a572d8be 542
c19d1320 543 return ("localhost");
44a47c6e 544}
545
98829f69 546const char *
547uniqueHostname(void)
548{
bf95c10a 549 debugs(21, 3, " Config: '" << Config.uniqueHostname << "'");
98829f69 550 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
551}
552
2f8abb64 553/** leave a privileged section. (Give up any privilegies)
30a4f2a8 554 * Routines that need privilegies can rap themselves in enter_suid()
555 * and leave_suid()
556 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 557 */
b8d8561b 558void
0673c0ba 559leave_suid(void)
12b9e9b1 560{
36584579 561 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
62e76326 562
e3d74828 563 if (Config.effectiveGroup) {
e3d74828 564#if HAVE_SETGROUPS
e3d74828 565 setgroups(1, &Config2.effectiveGroupID);
e3d74828 566#endif
567
b69e9ffa
AJ
568 if (setgid(Config2.effectiveGroupID) < 0) {
569 int xerrno = errno;
d816f28d 570 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
b69e9ffa 571 }
e3d74828 572 }
573
12b9e9b1 574 if (geteuid() != 0)
62e76326 575 return;
576
12b9e9b1 577 /* Started as a root, check suid option */
aee3523a 578 if (Config.effectiveUser == nullptr)
62e76326 579 return;
580
36584579 581 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
62e76326 582
e3d74828 583 if (!Config.effectiveGroup) {
62e76326 584
b69e9ffa
AJ
585 if (setgid(Config2.effectiveGroupID) < 0) {
586 int xerrno = errno;
d816f28d 587 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
b69e9ffa 588 }
62e76326 589
e3d74828 590 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
d816f28d 591 debugs(50, DBG_CRITICAL, "ERROR: initgroups: unable to set groups for User " <<
bf8fe701 592 Config.effectiveUser << " and Group " <<
593 (unsigned) Config2.effectiveGroupID << "");
e3d74828 594 }
595 }
62e76326 596
234967c9 597#if HAVE_SETRESUID
989393f2 598 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0) {
599 const auto xerrno = errno;
600 fatalf("FATAL: setresuid: %s", xstrerr(xerrno));
601 }
62e76326 602
234967c9 603#elif HAVE_SETEUID
989393f2 604 if (seteuid(Config2.effectiveUserID) < 0) {
605 const auto xerrno = errno;
606 fatalf("FATAL: seteuid: %s", xstrerr(xerrno));
607 }
62e76326 608
234967c9 609#else
989393f2 610 if (setuid(Config2.effectiveUserID) < 0) {
611 const auto xerrno = errno;
612 fatalf("FATAL: setuid: %s", xstrerr(xerrno));
613 }
62e76326 614
fc68f6b1 615#endif
fc68f6b1 616
ff2afd7f 617 restoreCapabilities(true);
321223fe 618 setTraceability();
234967c9 619}
620
30a4f2a8 621/* Enter a privilegied section */
b8d8561b 622void
0673c0ba 623enter_suid(void)
234967c9 624{
77468ee5 625 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
234967c9 626#if HAVE_SETRESUID
989393f2 627 if (setresuid((uid_t)-1, 0, (uid_t)-1) < 0) {
628 const auto xerrno = errno;
629 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno));
630 }
234967c9 631#else
62e76326 632
30043719
HS
633 if (setuid(0) < 0) {
634 const auto xerrno = errno;
635 debugs(21, 3, "setuid(0) failed: " << xstrerr(xerrno));
636 }
234967c9 637#endif
62ae0622 638
321223fe 639 setTraceability();
234967c9 640}
641
2f8abb64 642/* Give up the possibility to gain privilegies.
30a4f2a8 643 * this should be used before starting a sub process
644 */
b8d8561b 645void
0673c0ba 646no_suid(void)
234967c9 647{
648 uid_t uid;
30a4f2a8 649 leave_suid();
234967c9 650 uid = geteuid();
61beade2 651 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root privileges forever");
62e76326 652
b69e9ffa
AJ
653 if (setuid(0) < 0) {
654 int xerrno = errno;
655 debugs(50, DBG_IMPORTANT, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno));
656 }
62e76326 657
b69e9ffa
AJ
658 if (setuid(uid) < 0) {
659 int xerrno = errno;
660 debugs(50, DBG_IMPORTANT, "ERROR: no_suid: setuid(" << uid << "): " << xstrerr(xerrno));
661 }
62e76326 662
ff2afd7f 663 restoreCapabilities(false);
321223fe 664 setTraceability();
12b9e9b1 665}
ccff9601 666
a2c48c98 667bool
7de94c8c 668IamMasterProcess()
a2c48c98 669{
7de94c8c
AR
670 return KidIdentifier == 0;
671}
672
673bool
674IamWorkerProcess()
675{
676 // when there is only one process, it has to be the worker
13aeac35 677 if (opt_no_daemon || Config.workers == 0)
7de94c8c
AR
678 return true;
679
095ec2b1
AR
680 return TheProcessKind == pkWorker;
681}
682
683bool
684IamDiskProcess()
685{
686 return TheProcessKind == pkDisker;
7de94c8c
AR
687}
688
96c2bb61
AR
689bool
690InDaemonMode()
691{
692 return !opt_no_daemon && Config.workers > 0;
693}
694
7de94c8c
AR
695bool
696UsingSmp()
697{
095ec2b1 698 return InDaemonMode() && NumberOfKids() > 1;
7de94c8c
AR
699}
700
701bool
702IamCoordinatorProcess()
703{
095ec2b1 704 return TheProcessKind == pkCoordinator;
7de94c8c
AR
705}
706
707bool
708IamPrimaryProcess()
709{
710 // when there is only one process, it has to be primary
13aeac35 711 if (opt_no_daemon || Config.workers == 0)
7de94c8c
AR
712 return true;
713
714 // when there is a master and worker process, the master delegates
715 // primary functions to its only kid
254912f3 716 if (NumberOfKids() == 1)
7de94c8c 717 return IamWorkerProcess();
a2c48c98 718
7de94c8c
AR
719 // in SMP mode, multiple kids delegate primary functions to the coordinator
720 return IamCoordinatorProcess();
a2c48c98
AR
721}
722
96c2bb61
AR
723int
724NumberOfKids()
725{
726 // no kids in no-daemon mode
727 if (!InDaemonMode())
728 return 0;
729
095ec2b1
AR
730 // XXX: detect and abort when called before workers/cache_dirs are parsed
731
14911a4e 732 const int rockDirs = Config.cacheSwap.n_strands;
095ec2b1
AR
733
734 const bool needCoord = Config.workers > 1 || rockDirs > 0;
735 return (needCoord ? 1 : 0) + Config.workers + rockDirs;
736}
96c2bb61 737
1fdc4f42 738SBuf
095ec2b1
AR
739ProcessRoles()
740{
1fdc4f42 741 SBuf roles;
095ec2b1
AR
742 if (IamMasterProcess())
743 roles.append(" master");
744 if (IamCoordinatorProcess())
745 roles.append(" coordinator");
746 if (IamWorkerProcess())
747 roles.append(" worker");
748 if (IamDiskProcess())
749 roles.append(" disker");
750 return roles;
96c2bb61
AR
751}
752
f3f0f563
AJ
753/* A little piece of glue for odd systems */
754#ifndef RLIMIT_NOFILE
755#ifdef RLIMIT_OFILE
756#define RLIMIT_NOFILE RLIMIT_OFILE
757#endif
758#endif
7690e8eb 759
f3f0f563 760/** Figure out the number of supported filedescriptors */
b8d8561b 761void
0673c0ba 762setMaxFD(void)
c4fb974e 763{
f3f0f563 764#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
8527a56f 765
9064ed81
A
766 /* On Linux with 64-bit file support the sys/resource.h header
767 * uses #define to change the function definition to require rlimit64
768 */
8527a56f
AJ
769#if defined(getrlimit)
770 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
771#else
c4fb974e 772 struct rlimit rl;
8527a56f
AJ
773#endif
774
c4fb974e 775 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
b69e9ffa
AJ
776 int xerrno = errno;
777 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
f3f0f563 778 } else if (Config.max_filedescriptors > 0) {
91a04222 779#if USE_SELECT
0979b3a6 780 /* select() breaks if this gets set too big */
1b7fae06 781 if (Config.max_filedescriptors > FD_SETSIZE) {
0979b3a6 782 rl.rlim_cur = FD_SETSIZE;
1b7fae06
AJ
783 debugs(50, DBG_CRITICAL, "WARNING: 'max_filedescriptors " << Config.max_filedescriptors << "' does not work with select()");
784 } else
0979b3a6
AJ
785#endif
786 rl.rlim_cur = Config.max_filedescriptors;
62e76326 787 if (rl.rlim_cur > rl.rlim_max)
f3f0f563
AJ
788 rl.rlim_max = rl.rlim_cur;
789 if (setrlimit(RLIMIT_NOFILE, &rl)) {
b69e9ffa
AJ
790 int xerrno = errno;
791 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
f3f0f563
AJ
792 getrlimit(RLIMIT_NOFILE, &rl);
793 rl.rlim_cur = rl.rlim_max;
794 if (setrlimit(RLIMIT_NOFILE, &rl)) {
b69e9ffa
AJ
795 xerrno = errno;
796 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
f3f0f563 797 }
62e76326 798 }
c4fb974e 799 }
f3f0f563 800 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
b69e9ffa
AJ
801 int xerrno = errno;
802 debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
c4fb974e 803 } else {
f3f0f563
AJ
804 Squid_MaxFD = rl.rlim_cur;
805 }
62e76326 806
f3f0f563
AJ
807#endif /* HAVE_SETRLIMIT */
808}
62e76326 809
f3f0f563
AJ
810void
811setSystemLimits(void)
812{
be266cb2 813#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
f3f0f563 814 /* limit system filedescriptors to our own limit */
8527a56f
AJ
815
816 /* On Linux with 64-bit file support the sys/resource.h header
817 * uses #define to change the function definition to require rlimit64
818 */
819#if defined(getrlimit)
820 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
821#else
f3f0f563 822 struct rlimit rl;
8527a56f
AJ
823#endif
824
f3f0f563 825 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
b69e9ffa
AJ
826 int xerrno = errno;
827 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
f3f0f563
AJ
828 } else {
829 rl.rlim_cur = Squid_MaxFD;
830 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
b69e9ffa 831 int xerrno = errno;
5d821589 832 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno));
62e76326 833 fatal_dump(tmp_error_buf);
834 }
c4fb974e 835 }
30a4f2a8 836#endif /* HAVE_SETRLIMIT */
837
a396d1f8 838#if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
30a4f2a8 839 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
b69e9ffa
AJ
840 int xerrno = errno;
841 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno));
88738790 842 } else if (rl.rlim_max > rl.rlim_cur) {
f53969cc 843 rl.rlim_cur = rl.rlim_max; /* set it to the max */
62e76326 844
845 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
b69e9ffa 846 int xerrno = errno;
5d821589 847 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno));
62e76326 848 fatal_dump(tmp_error_buf);
849 }
30a4f2a8 850 }
851#endif /* RLIMIT_DATA */
f3f0f563 852 if (Config.max_filedescriptors > Squid_MaxFD) {
d816f28d 853 debugs(50, DBG_IMPORTANT, "WARNING: Could not increase the number of filedescriptors");
f3f0f563
AJ
854 }
855
a396d1f8 856#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
ad7ef91a 857 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
b69e9ffa
AJ
858 int xerrno = errno;
859 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno));
88738790 860 } else if (rl.rlim_max > rl.rlim_cur) {
f53969cc 861 rl.rlim_cur = rl.rlim_max; /* set it to the max */
62e76326 862
863 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
20c05acd 864 int xerrno = errno;
5d821589 865 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno));
62e76326 866 fatal_dump(tmp_error_buf);
867 }
ad7ef91a 868 }
869#endif /* RLIMIT_VMEM */
c4fb974e 870}
3a57089e 871
b8d8561b 872void
ea3a2a69 873squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 874{
875#if HAVE_SIGACTION
62e76326 876
30a4f2a8 877 struct sigaction sa;
878 sa.sa_handler = func;
879 sa.sa_flags = flags;
880 sigemptyset(&sa.sa_mask);
62e76326 881
aee3523a 882 if (sigaction(sig, &sa, nullptr) < 0) {
b69e9ffa
AJ
883 int xerrno = errno;
884 debugs(50, DBG_CRITICAL, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerr(xerrno));
885 }
30a4f2a8 886#else
7aa9bb3e 887#if _SQUID_WINDOWS_
06648839 888 /*
889 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
890 are supported, so we must care of don't call signal() for other value.
891 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
892 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
893 */
894 switch (sig) {
895
896 case SIGINT:
897
898 case SIGILL:
899
900 case SIGFPE:
901
902 case SIGTERM:
903
904 case SIGBREAK:
905
906 case SIGABRT:
907 break;
908
909 case SIGSEGV:
910 WIN32_ExceptionHandlerInit();
911 break;
912
913 case SIGBUS:
914 WIN32_ExceptionHandlerInit();
915 return;
916 break; /* Nor reached */
917
918 default:
919 return;
920 break; /* Nor reached */
921 }
922
923#endif
62e76326 924
06648839 925 signal(sig, func);
62e76326 926
30a4f2a8 927#endif
928}
396c5745 929
70364f29 930void
931logsFlush(void)
932{
016c612a
AJ
933 if (DebugStream())
934 fflush(DebugStream());
70364f29 935}
88738790 936
a00a7c85 937void
6bbf9cc4 938debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 939{
6bbf9cc4 940 assert(label && obj && pm);
10201568 941 MemBuf mb;
2fe7eff9 942 mb.init();
10201568 943 (*pm) (obj, &mb);
bf8fe701 944 debugs(section, level, "" << label << "" << mb.buf << "");
2fe7eff9 945 mb.clean();
a00a7c85 946}
d548ee64 947
0e70aa1e 948void
949parseEtcHosts(void)
950{
0e70aa1e 951 char buf[1024];
952 char buf2[512];
953 char *nt = buf;
954 char *lt = buf;
fa2bfbab 955
b69e9ffa 956 if (!Config.etcHostsPath)
62e76326 957 return;
958
0e70aa1e 959 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 960 return;
961
b69e9ffa 962 FILE *fp = fopen(Config.etcHostsPath, "r");
62e76326 963
b69e9ffa
AJ
964 if (!fp) {
965 int xerrno = errno;
1bff41b7 966 debugs(1, DBG_IMPORTANT, "parseEtcHosts: '" << Config.etcHostsPath << "' : " << xstrerr(xerrno));
62e76326 967 return;
0e70aa1e 968 }
62e76326 969
be266cb2 970#if _SQUID_WINDOWS_
c4aefe96 971 setmode(fileno(fp), O_TEXT);
972#endif
62e76326 973
f53969cc 974 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 975
f53969cc 976 if (buf[0] == '#') /* MS-windows likes to add comments */
c31616ae 977 continue;
978
f53969cc 979 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 980
981 lt = buf;
982
1bff41b7 983 char *addr = buf;
62e76326 984
bf8fe701 985 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
62e76326 986
987 nt = strpbrk(lt, w_space);
988
aee3523a 989 if (nt == nullptr) /* empty line */
62e76326 990 continue;
991
f53969cc 992 *nt = '\0'; /* null-terminate the address */
62e76326 993
bf8fe701 994 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
62e76326 995
996 lt = nt + 1;
997
1bff41b7
AJ
998 SBufList hosts;
999
62e76326 1000 while ((nt = strpbrk(lt, w_space))) {
aee3523a 1001 char *host = nullptr;
62e76326 1002
f53969cc 1003 if (nt == lt) { /* multiple spaces */
bf8fe701 1004 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
62e76326 1005 lt = nt + 1;
1006 continue;
1007 }
1008
1009 *nt = '\0';
bf8fe701 1010 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
62e76326 1011
532e5dd4
AJ
1012 /* For IPV6 addresses also check for a colon */
1013 if (Config.appendDomain && !strchr(lt, '.') && !strchr(lt, ':')) {
62e76326 1014 /* I know it's ugly, but it's only at reconfig */
0a84e4fb
AJ
1015 strncpy(buf2, lt, sizeof(buf2)-1);
1016 strncat(buf2, Config.appendDomain, sizeof(buf2) - strlen(lt) - 1);
50e746f3 1017 buf2[sizeof(buf2)-1] = '\0';
62e76326 1018 host = buf2;
1019 } else {
1020 host = lt;
1021 }
1022
f6a72b33
AJ
1023 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1024 /* invalid address, continuing is useless */
1bff41b7 1025 hosts.clear();
f6a72b33
AJ
1026 break;
1027 }
1bff41b7 1028 hosts.emplace_back(SBuf(host));
62e76326 1029
1030 lt = nt + 1;
1031 }
1032
1bff41b7 1033 if (!hosts.empty())
f6a72b33 1034 fqdncacheAddEntryFromHosts(addr, hosts);
0e70aa1e 1035 }
62e76326 1036
1f3c7397 1037 fclose (fp);
0e70aa1e 1038}
52f772de 1039
1040int
1041getMyPort(void)
1042{
fa720bfb 1043 AnyP::PortCfgPointer p;
aee3523a 1044 if ((p = HttpPortList) != nullptr) {
c4ac4197 1045 // skip any special interception ports
aee3523a 1046 while (p != nullptr && p->flags.isIntercepted())
af5ebaf4 1047 p = p->next;
aee3523a 1048 if (p != nullptr)
4dd643d5 1049 return p->s.port();
af5ebaf4 1050 }
62e76326 1051
aee3523a 1052 if ((p = FtpPortList) != nullptr) {
547f3031 1053 // skip any special interception ports
aee3523a 1054 while (p != nullptr && p->flags.isIntercepted())
547f3031 1055 p = p->next;
aee3523a 1056 if (p != nullptr)
547f3031
AR
1057 return p->s.port();
1058 }
1059
af5ebaf4
AJ
1060 debugs(21, DBG_CRITICAL, "ERROR: No forward-proxy ports configured.");
1061 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
52f772de 1062}
d860a1aa 1063
c642c141
AJ
1064/*
1065 * Set the umask to at least the given mask. This is in addition
1066 * to the umask set at startup
1067 */
1068void
1069setUmask(mode_t mask)
1070{
1071 // No way to get the current umask value without setting it.
1072 static const mode_t orig_umask = umask(mask); // once, to get
1073 umask(mask | orig_umask); // always, to set
1074}
d860a1aa 1075
1076/*
1077 * Inverse of strwordtok. Quotes a word if needed
1078 */
42419a95 1079void
d860a1aa 1080strwordquote(MemBuf * mb, const char *str)
1081{
1082 int quoted = 0;
62e76326 1083
d860a1aa 1084 if (strchr(str, ' ')) {
62e76326 1085 quoted = 1;
2fe7eff9 1086 mb->append("\"", 1);
d860a1aa 1087 }
62e76326 1088
d860a1aa 1089 while (*str) {
dc1af3cf 1090 int l = strcspn(str, "\"\\\n\r");
2fe7eff9 1091 mb->append(str, l);
62e76326 1092 str += l;
1093
26ac0430 1094 switch (*str) {
dc1af3cf 1095
1096 case '\n':
2fe7eff9 1097 mb->append("\\n", 2);
5db6bf73 1098 ++str;
dc1af3cf 1099 break;
1100
1101 case '\r':
2fe7eff9 1102 mb->append("\\r", 2);
5db6bf73 1103 ++str;
dc1af3cf 1104 break;
1105
1106 case '\0':
1107 break;
1108
1109 default:
2fe7eff9 1110 mb->append("\\", 1);
1111 mb->append(str, 1);
5db6bf73 1112 ++str;
dc1af3cf 1113 break;
62e76326 1114 }
d860a1aa 1115 }
62e76326 1116
d860a1aa 1117 if (quoted)
2fe7eff9 1118 mb->append("\"", 1);
d860a1aa 1119}
fc68f6b1 1120
1121void
1122keepCapabilities(void)
1123{
4106ed25 1124#if HAVE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
329ce686 1125 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
b7ac5457 1126 Ip::Interceptor.StopTransparency("capability setting has failed.");
fc68f6b1 1127 }
fc68f6b1 1128#endif
1129}
329ce686 1130
1131static void
ff2afd7f 1132restoreCapabilities(bool keep)
329ce686 1133{
4106ed25 1134#if HAVE_LIBCAP
c3487a77
HN
1135 cap_t caps;
1136 if (keep)
1137 caps = cap_get_proc();
1138 else
1139 caps = cap_init();
1140 if (!caps) {
b7ac5457 1141 Ip::Interceptor.StopTransparency("Can't get current capabilities");
9e008dda 1142 } else {
c3487a77
HN
1143 int ncaps = 0;
1144 int rc = 0;
1145 cap_value_t cap_list[10];
5db6bf73
FC
1146 cap_list[ncaps] = CAP_NET_BIND_SERVICE;
1147 ++ncaps;
4a751e2a 1148 if (Ip::Interceptor.TransparentActive() ||
653d9927
A
1149#if USE_LIBNETFILTERCONNTRACK
1150 // netfilter_conntrack requires CAP_NET_ADMIN to get client's CONNMARK
1151 Ip::Interceptor.InterceptActive() ||
1152#endif
9e27e206
SM
1153 Ip::Qos::TheConfig.isHitNfmarkActive() ||
1154 Ip::Qos::TheConfig.isAclNfmarkActive() ||
1155 Ip::Qos::TheConfig.isAclTosActive()) {
5db6bf73
FC
1156 cap_list[ncaps] = CAP_NET_ADMIN;
1157 ++ncaps;
fc32ce2e 1158 }
329ce686 1159
c3487a77
HN
1160 cap_clear_flag(caps, CAP_EFFECTIVE);
1161 rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1162 rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
329ce686 1163
c3487a77 1164 if (rc || cap_set_proc(caps) != 0) {
b7ac5457 1165 Ip::Interceptor.StopTransparency("Error enabling needed capabilities.");
b5bd96ce 1166 }
c3487a77 1167 cap_free(caps);
329ce686 1168 }
8a09e810 1169#elif _SQUID_LINUX_
4106ed25 1170 /* Linux requires syscap support from libcap. */
b7ac5457 1171 Ip::Interceptor.StopTransparency("Missing needed capability support.");
4106ed25 1172 (void)keep;
8b082ed9 1173#else
4106ed25 1174 /* Non-Linux transparent proxy works with or without libcap support. */
8b082ed9 1175 (void)keep;
4106ed25 1176#endif
329ce686 1177}
f53969cc 1178
dbf55289
CT
1179pid_t
1180WaitForOnePid(pid_t pid, PidStatus &status, int flags)
1181{
c633a6b0 1182#if _SQUID_WINDOWS_
c92fcbad 1183 return 0; // function not used on Windows
dbf55289
CT
1184#else
1185 return waitpid(pid, &status, flags);
1186#endif
1187}
5c634111 1188
d9cb4f7a 1189#if _SQUID_WINDOWS_ || _SQUID_MINGW_
e99fa721
EB
1190SBuf
1191WindowsErrorMessage(DWORD errorId)
1192{
1193 char *rawMessage = nullptr;
1194 const auto length = FormatMessage(
1195 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1196 FORMAT_MESSAGE_FROM_SYSTEM |
1197 FORMAT_MESSAGE_IGNORE_INSERTS,
1198 nullptr,
1199 errorId,
1200 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1201 static_cast<LPTSTR>(&rawMessage),
1202 0,
1203 nullptr);
1204 if (!length) {
1205 Must(!rawMessage); // nothing to LocalFree()
1206 return ToSBuf("windows error ", errorId);
1207 }
1208 const auto result = SBuf(rawMessage, length);
1209 LocalFree(rawMessage);
1210 return result;
1211}
d9cb4f7a 1212#endif // _SQUID_WINDOWS_ || _SQUID_MINGW_
e99fa721 1213