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