]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Prep for 3.0.STABLE14
[thirdparty/squid.git] / src / tools.cc
CommitLineData
30a4f2a8 1/*
262a0e14 2 * $Id$
30a4f2a8 3 *
4 * DEBUG: section 21 Misc Functions
5 * AUTHOR: Harvest Derived
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
30a4f2a8 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
26ac0430 23 *
30a4f2a8 24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
26ac0430 28 *
30a4f2a8 29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
019dd986 33 */
44a47c6e 34
35#include "squid.h"
07f765a3 36#include "ProtoPort.h"
c8f4eac4 37#include "SwapDir.h"
528b2c61 38#include "fde.h"
0eb49b6d 39#include "MemBuf.h"
d295d770 40#include "wordlist.h"
985c86bc 41#include "SquidTime.h"
85944c1c 42#include "ip/IpIntercept.h"
44a47c6e 43
329ce686 44#ifdef _SQUID_LINUX_
45#if HAVE_SYS_CAPABILITY_H
fc68f6b1 46#undef _POSIX_SOURCE
47/* Ugly glue to get around linux header madness colliding with glibc */
48#define _LINUX_TYPES_H
49#define _LINUX_FS_H
50typedef uint32_t __u32;
51#include <sys/capability.h>
52#endif
329ce686 53#endif
fc68f6b1 54
62ae0622 55#if HAVE_SYS_PRCTL_H
56#include <sys/prctl.h>
57#endif
58
090089c4 59#define DEAD_MSG "\
c5c666ab 60The Squid Cache (version %s) died.\n\
090089c4 61\n\
c5c666ab 62You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 63If a core file was created (possibly in the swap directory),\n\
b8de7ebe 64please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
784219b8 65and report the trace back to squid-bugs@squid-cache.org.\n\
090089c4 66\n\
67Thanks!\n"
68
f5b8bbc4 69static void fatal_common(const char *);
137ee196 70static void fatalvf(const char *fmt, va_list args);
f5b8bbc4 71static void mail_warranty(void);
63986a85 72#if MEM_GEN_TRACE
399e85ea 73extern void log_trace_done();
63986a85 74extern void log_trace_init(char *);
399e85ea 75#endif
329ce686 76static void restoreCapabilities(int keep);
24382924 77
941a3077 78#ifdef _SQUID_LINUX_
79/* Workaround for crappy glic header files */
e6ccf245 80SQUIDCEXTERN int backtrace(void *, int);
81SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
82SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
941a3077 83#endif /* _SQUID_LINUX */
84
8fd63c35 85SQUIDCEXTERN void (*failure_notify) (const char *);
7e3ce7b9 86
4a5a6c62 87void
429fdbec 88releaseServerSockets(void)
89{
812ed90c 90 int i;
429fdbec 91 /* Release the main ports as early as possible */
62e76326 92
812ed90c 93 for (i = 0; i < NHttpSockets; i++) {
62e76326 94 if (HttpSockets[i] >= 0)
95 close(HttpSockets[i]);
812ed90c 96 }
62e76326 97
429fdbec 98 if (theInIcpConnection >= 0)
62e76326 99 close(theInIcpConnection);
100
429fdbec 101 if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
62e76326 102 close(theOutIcpConnection);
429fdbec 103}
104
b8d8561b 105static char *
0673c0ba 106dead_msg(void)
090089c4 107{
95d659f0 108 LOCAL_ARRAY(char, msg, 1024);
56878878 109 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 110 return msg;
111}
112
24382924 113static void
0673c0ba 114mail_warranty(void)
090089c4 115{
019dd986 116 FILE *fp = NULL;
6e40f263 117 static char command[256];
b99a6dec 118#if HAVE_MKSTEMP
62e76326 119
b99a6dec 120 char filename[] = "/tmp/squid-XXXXXX";
121 int tfd = mkstemp(filename);
62e76326 122
b99a6dec 123 if (tfd < 0)
62e76326 124 return;
125
b99a6dec 126 if ((fp = fdopen(tfd, "w")) == NULL)
62e76326 127 return;
128
b99a6dec 129#else
62e76326 130
b99a6dec 131 char *filename;
62e76326 132
7dbca7a4 133 if ((filename = tempnam(NULL, APP_SHORTNAME)) == NULL)
62e76326 134 return;
135
6e40f263 136 if ((fp = fopen(filename, "w")) == NULL)
62e76326 137 return;
138
b99a6dec 139#endif
62e76326 140
abacf776 141 if (Config.EmailFrom)
142 fprintf(fp, "From: %s\n", Config.EmailFrom);
143 else
7dbca7a4 144 fprintf(fp, "From: %s@%s\n", APP_SHORTNAME, uniqueHostname());
62e76326 145
edae7bc0 146 fprintf(fp, "To: %s\n", Config.adminEmail);
62e76326 147
6e40f263 148 fprintf(fp, "Subject: %s\n", dead_msg());
62e76326 149
6e40f263 150 fclose(fp);
62e76326 151
d084bf20 152 snprintf(command, 256, "%s %s < %s", Config.EmailProgram, Config.adminEmail, filename);
62e76326 153
26ac0430 154 if (system(command)) {} /* XXX should avoid system(3) */
62e76326 155
6e40f263 156 unlink(filename);
090089c4 157}
158
4a5a6c62 159void
43c3424b 160dumpMallocStats(void)
3f43b19b 161{
88738790 162#if HAVE_MSTATS && HAVE_GNUMALLOC_H
62e76326 163
88738790 164 struct mstats ms = mstats();
165 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
62e76326 166 (int) (ms.bytes_total >> 10));
88738790 167 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
62e76326 168 (int) (ms.bytes_free >> 10),
169 percent(ms.bytes_free, ms.bytes_total));
eb824054 170#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
62e76326 171
3f43b19b 172 struct mallinfo mp;
30a4f2a8 173 int t;
62e76326 174
3f43b19b 175 if (!do_mallinfo)
62e76326 176 return;
177
3f43b19b 178 mp = mallinfo();
62e76326 179
7dbca7a4 180 fprintf(debug_log, "Memory usage for "APP_SHORTNAME" via mallinfo():\n");
62e76326 181
e4049756 182 fprintf(debug_log, "\ttotal space in arena: %6ld KB\n",
183 (long)mp.arena >> 10);
62e76326 184
e4049756 185 fprintf(debug_log, "\tOrdinary blocks: %6ld KB %6ld blks\n",
186 (long)mp.uordblks >> 10, (long)mp.ordblks);
62e76326 187
e4049756 188 fprintf(debug_log, "\tSmall blocks: %6ld KB %6ld blks\n",
189 (long)mp.usmblks >> 10, (long)mp.smblks);
62e76326 190
e4049756 191 fprintf(debug_log, "\tHolding blocks: %6ld KB %6ld blks\n",
192 (long)mp.hblkhd >> 10, (long)mp.hblks);
62e76326 193
e4049756 194 fprintf(debug_log, "\tFree Small blocks: %6ld KB\n",
195 (long)mp.fsmblks >> 10);
62e76326 196
e4049756 197 fprintf(debug_log, "\tFree Ordinary blocks: %6ld KB\n",
198 (long)mp.fordblks >> 10);
62e76326 199
30a4f2a8 200 t = mp.uordblks + mp.usmblks + mp.hblkhd;
62e76326 201
9e4ad609 202 fprintf(debug_log, "\tTotal in use: %6d KB %d%%\n",
62e76326 203 t >> 10, percent(t, mp.arena));
204
30a4f2a8 205 t = mp.fsmblks + mp.fordblks;
62e76326 206
9e4ad609 207 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
62e76326 208 t >> 10, percent(t, mp.arena));
209
6a9f6389 210#if HAVE_STRUCT_MALLINFO_MXFAST
62e76326 211
9e4ad609 212 fprintf(debug_log, "\tmax size of small blocks:\t%d\n",
62e76326 213 mp.mxfast);
214
9e4ad609 215 fprintf(debug_log, "\tnumber of small blocks in a holding block:\t%d\n",
62e76326 216 mp.nlblks);
217
9e4ad609 218 fprintf(debug_log, "\tsmall block rounding factor:\t%d\n",
62e76326 219 mp.grain);
220
9e4ad609 221 fprintf(debug_log, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
62e76326 222 mp.uordbytes);
223
9e4ad609 224 fprintf(debug_log, "\tnumber of ordinary blocks allocated:\t%d\n",
62e76326 225 mp.allocated);
226
9e4ad609 227 fprintf(debug_log, "\tbytes used in maintaining the free tree:\t%d\n",
62e76326 228 mp.treeoverhead);
229
6a9f6389 230#endif /* HAVE_STRUCT_MALLINFO_MXFAST */
3f43b19b 231#endif /* HAVE_MALLINFO */
232}
30a4f2a8 233
f2908497 234void
62e76326 235
f2908497 236squid_getrusage(struct rusage *r)
f0f81709 237{
62e76326 238
8da94b66 239 memset(r, '\0', sizeof(struct rusage));
30a4f2a8 240#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
cd19f0b6 241#ifdef _SQUID_SOLARIS_
242 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
243 enter_suid();
244#endif
62e76326 245
f2908497 246 getrusage(RUSAGE_SELF, r);
cd19f0b6 247#ifdef _SQUID_SOLARIS_
62e76326 248
cd19f0b6 249 leave_suid();
250#endif
56983a01 251#endif
f2908497 252}
253
254double
62e76326 255
f2908497 256rusage_cputime(struct rusage *r)
257{
258 return (double) r->ru_stime.tv_sec +
62e76326 259 (double) r->ru_utime.tv_sec +
260 (double) r->ru_stime.tv_usec / 1000000.0 +
261 (double) r->ru_utime.tv_usec / 1000000.0;
f2908497 262}
263
ec603b25 264/* Hack for some HP-UX preprocessors */
265#ifndef HAVE_GETPAGESIZE
266#define HAVE_GETPAGESIZE 0
267#endif
268
f2908497 269int
62e76326 270
f2908497 271rusage_maxrss(struct rusage *r)
272{
4fdc3986 273#if defined(_SQUID_SGI_) && _ABIAPI
274 return r->ru_pad[0];
275#elif defined(_SQUID_SGI_)
62e76326 276
f2908497 277 return r->ru_maxrss;
278#elif defined(_SQUID_OSF_)
62e76326 279
a6e0ad1e 280 return r->ru_maxrss;
281#elif defined(_SQUID_AIX_)
282
f2908497 283 return r->ru_maxrss;
284#elif defined(BSD4_4)
62e76326 285
f2908497 286 return r->ru_maxrss;
6b8e7481 287#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
62e76326 288
f2908497 289 return (r->ru_maxrss * getpagesize()) >> 10;
c7a1083d 290#elif defined(PAGESIZE)
62e76326 291
c7a1083d 292 return (r->ru_maxrss * PAGESIZE) >> 10;
8505e57b 293#else
62e76326 294
8505e57b 295 return r->ru_maxrss;
f2908497 296#endif
297}
298
299int
62e76326 300
f2908497 301rusage_pagefaults(struct rusage *r)
302{
4fdc3986 303#if defined(_SQUID_SGI_) && _ABIAPI
304 return r->ru_pad[5];
305#else
62e76326 306
f2908497 307 return r->ru_majflt;
4fdc3986 308#endif
f2908497 309}
310
311
4a5a6c62 312void
f2908497 313PrintRusage(void)
314{
62e76326 315
f2908497 316 struct rusage rusage;
317 squid_getrusage(&rusage);
2b906e48 318 fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
62e76326 319 rusage_cputime(&rusage),
320 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
321 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
f2908497 322 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
62e76326 323 rusage_maxrss(&rusage));
f2908497 324 fprintf(debug_log, "Page faults with physical i/o: %d\n",
62e76326 325 rusage_pagefaults(&rusage));
f0f81709 326}
327
03d7b07f 328
b8d8561b 329void
330death(int sig)
44a47c6e 331{
0e08ce4b 332 if (sig == SIGSEGV)
62e76326 333 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 334 else if (sig == SIGBUS)
62e76326 335 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 336 else
62e76326 337 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
0b4639af 338
339#ifdef PRINT_STACK_TRACE
340#ifdef _SQUID_HPUX_
341 {
62e76326 342 extern void U_STACK_TRACE(void); /* link with -lcl */
343 fflush(debug_log);
344 dup2(fileno(debug_log), 2);
345 U_STACK_TRACE();
0b4639af 346 }
62e76326 347
0b4639af 348#endif /* _SQUID_HPUX_ */
349#ifdef _SQUID_SOLARIS_
4f07153c 350 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
62e76326 351 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
352 fflush(debug_log);
353 dup2(fileno(debug_log), fileno(stdout));
354 opcom_stack_trace();
355 fflush(stdout);
0b4639af 356 }
62e76326 357
0b4639af 358#endif /* _SQUID_SOLARIS_ */
ce3d30fb 359#if HAVE_BACKTRACE_SYMBOLS_FD
360 {
62e76326 361 static void *(callarray[8192]);
362 int n;
363 n = backtrace(callarray, 8192);
364 backtrace_symbols_fd(callarray, n, fileno(debug_log));
ce3d30fb 365 }
62e76326 366
ce3d30fb 367#endif
0b4639af 368#endif /* PRINT_STACK_TRACE */
369
06648839 370#if SA_RESETHAND == 0 && !defined(_SQUID_MSWIN_)
44a47c6e 371 signal(SIGSEGV, SIG_DFL);
62e76326 372
44a47c6e 373 signal(SIGBUS, SIG_DFL);
62e76326 374
0e08ce4b 375 signal(sig, SIG_DFL);
62e76326 376
30a4f2a8 377#endif
62e76326 378
429fdbec 379 releaseServerSockets();
62e76326 380
e3ef2b09 381 storeDirWriteCleanLogs(0);
62e76326 382
4b0f5de8 383 if (!shutting_down) {
384 PrintRusage();
62e76326 385
4b0f5de8 386 dumpMallocStats();
387 }
62e76326 388
6e40f263 389 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
62e76326 390 /* skip if more than 10 days old */
391
392 if (Config.adminEmail)
393 mail_warranty();
329ce686 394
395 puts(dead_msg());
6e40f263 396 }
62e76326 397
776ff02c 398 if (shutting_down)
329ce686 399 exit(1);
776ff02c 400
44a47c6e 401 abort();
402}
403
404
b8d8561b 405void
23d92c64 406sigusr2_handle(int sig)
090089c4 407{
30a4f2a8 408 static int state = 0;
545f551a 409 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
62e76326 410
30a4f2a8 411 if (state == 0) {
2bf05976 412#ifndef MEM_GEN_TRACE
d7298d24 413 Debug::parseOptions("ALL,7");
2bf05976 414#else
62e76326 415
416 log_trace_done();
63986a85 417#endif
62e76326 418
419 state = 1;
30a4f2a8 420 } else {
2bf05976 421#ifndef MEM_GEN_TRACE
3dc275d6 422 Debug::parseOptions(Config.debugOptions);
2bf05976 423#else
62e76326 424
425 log_trace_init("/tmp/squid.alloc");
63986a85 426#endif
62e76326 427
428 state = 0;
30a4f2a8 429 }
62e76326 430
30a4f2a8 431#if !HAVE_SIGACTION
e504b0a7 432 if (signal(sig, sigusr2_handle) == SIG_ERR) /* reinstall */
29827b3e 433 debugs(50, 0, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerror());
62e76326 434
090089c4 435#endif
436}
437
24382924 438static void
0ee4272b 439fatal_common(const char *message)
090089c4 440{
db40ae20 441#if HAVE_SYSLOG
6b8e7481 442 syslog(LOG_ALERT, "%s", message);
db40ae20 443#endif
62e76326 444
9bc73deb 445 fprintf(debug_log, "FATAL: %s\n", message);
62e76326 446
9bc73deb 447 if (opt_debug_stderr > 0 && debug_log != stderr)
62e76326 448 fprintf(stderr, "FATAL: %s\n", message);
449
c5c666ab 450 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
62e76326 451 version_string);
452
2c47cf74 453 fflush(debug_log);
62e76326 454
9e4ad609 455 PrintRusage();
62e76326 456
9e4ad609 457 dumpMallocStats();
090089c4 458}
459
460/* fatal */
b8d8561b 461void
0ee4272b 462fatal(const char *message)
090089c4 463{
634243ef
AJ
464 /* suppress secondary errors from the dying */
465 shutting_down = 1;
466
429fdbec 467 releaseServerSockets();
b2c141d4 468 /* check for store_dirs_rebuilding because fatal() is often
d399be0e 469 * used in early initialization phases, long before we ever
470 * get to the store log. */
62e76326 471
bef81ea5 472 /* XXX: this should be turned into a callback-on-fatal, or
473 * a mandatory-shutdown-event or something like that.
474 * - RBC 20060819
475 */
476
975b5060 477 /*
478 * DPW 2007-07-06
479 * Call leave_suid() here to make sure that swap.state files
480 * are written as the effective user, rather than root. Squid
481 * may take on root privs during reconfigure. If squid.conf
482 * contains a "Bungled" line, fatal() will be called when the
483 * process still has root privs.
484 */
7e0f82f2 485 leave_suid();
975b5060 486
bef81ea5 487 if (0 == StoreController::store_dirs_rebuilding)
62e76326 488 storeDirWriteCleanLogs(0);
489
090089c4 490 fatal_common(message);
62e76326 491
776ff02c 492 exit(1);
090089c4 493}
494
137ee196 495/* printf-style interface for fatal */
137ee196 496void
497fatalf(const char *fmt,...)
498{
499 va_list args;
500 va_start(args, fmt);
137ee196 501 fatalvf(fmt, args);
502 va_end(args);
503}
504
505
506/* used by fatalf */
507static void
af6a12ee
AJ
508fatalvf(const char *fmt, va_list args)
509{
137ee196 510 static char fatal_str[BUFSIZ];
511 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
512 fatal(fatal_str);
513}
514
090089c4 515/* fatal with dumping core */
b8d8561b 516void
af6a12ee
AJ
517fatal_dump(const char *message)
518{
7e3ce7b9 519 failure_notify = NULL;
429fdbec 520 releaseServerSockets();
62e76326 521
090089c4 522 if (message)
62e76326 523 fatal_common(message);
524
776ff02c 525 /*
526 * Call leave_suid() here to make sure that swap.state files
527 * are written as the effective user, rather than root. Squid
528 * may take on root privs during reconfigure. If squid.conf
529 * contains a "Bungled" line, fatal() will be called when the
530 * process still has root privs.
531 */
532 leave_suid();
533
4a69c163 534 if (opt_catch_signals)
62e76326 535 storeDirWriteCleanLogs(0);
536
090089c4 537 abort();
538}
539
b8d8561b 540void
af6a12ee
AJ
541debug_trap(const char *message)
542{
4a69c163 543 if (!opt_catch_signals)
62e76326 544 fatal_dump(message);
545
a3d5953d 546 _db_print("WARNING: %s\n", message);
85b701ed 547}
548
b8d8561b 549void
af6a12ee
AJ
550sig_child(int sig)
551{
a50bfe93 552#ifndef _SQUID_MSWIN_
30a4f2a8 553#ifdef _SQUID_NEXT_
554 union wait status;
555#else
62e76326 556
090089c4 557 int status;
090089c4 558#endif
62e76326 559
ff8d0ea6 560 pid_t pid;
090089c4 561
30a4f2a8 562 do {
563#ifdef _SQUID_NEXT_
62e76326 564 pid = wait3(&status, WNOHANG, NULL);
090089c4 565#else
62e76326 566
567 pid = waitpid(-1, &status, WNOHANG);
090089c4 568#endif
62e76326 569 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 570#if HAVE_SIGACTION
62e76326 571
30a4f2a8 572 } while (pid > 0);
62e76326 573
234967c9 574#else
62e76326 575
576 }
577
3d0ac046 578 while (pid > 0 || (pid < 0 && errno == EINTR));
30a4f2a8 579 signal(sig, sig_child);
62e76326 580
a50bfe93 581#endif
234967c9 582#endif
30a4f2a8 583}
44a47c6e 584
0ee4272b 585const char *
0673c0ba 586getMyHostname(void)
44a47c6e 587{
95d659f0 588 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 589 static int present = 0;
cc192b50 590 struct addrinfo *AI = NULL;
ad61a2b4 591 IpAddress sa;
62e76326 592
af85f811 593 if (Config.visibleHostname != NULL)
62e76326 594 return Config.visibleHostname;
595
d20b1cd0 596 if (present)
62e76326 597 return host;
598
d20b1cd0 599 host[0] = '\0';
62e76326 600
cc192b50 601 if (Config.Sockaddr.http && sa.IsAnyAddr())
602 sa = Config.Sockaddr.http->s;
62e76326 603
aa2b5399 604#if USE_SSL
62e76326 605
cc192b50 606 if (Config.Sockaddr.https && sa.IsAnyAddr())
607 sa = Config.Sockaddr.https->http.s;
62e76326 608
aa2b5399 609#endif
cc192b50 610
aa2b5399 611 /*
612 * If the first http_port address has a specific address, try a
613 * reverse DNS lookup on it.
614 */
26ac0430 615 if ( !sa.IsAnyAddr() ) {
62e76326 616
cc192b50 617 sa.GetAddrInfo(AI);
618 /* we are looking for a name. */
26ac0430 619 if (xgetnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, NULL, 0, NI_NAMEREQD ) == 0) {
62e76326 620 /* DNS lookup successful */
621 /* use the official name from DNS lookup */
cc192b50 622 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
bf8fe701 623
62e76326 624 present = 1;
625
cc192b50 626 sa.FreeAddrInfo(AI);
627
62e76326 628 if (strchr(host, '.'))
629 return host;
62e76326 630 }
631
cc192b50 632 sa.FreeAddrInfo(AI);
633 debugs(50, 1, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
26ac0430 634 } else {
cc192b50 635 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
636 debugs(50, 1, "WARNING: gethostname failed: " << xstrerror());
26ac0430 637 } else {
cc192b50 638 /* Verify that the hostname given resolves properly */
639 struct addrinfo hints;
640 memset(&hints, 0, sizeof(addrinfo));
641 hints.ai_flags = AI_CANONNAME;
642
26ac0430 643 if (xgetaddrinfo(host, NULL, NULL, &AI) == 0) {
cc192b50 644 /* DNS lookup successful */
645 /* use the official name from DNS lookup */
626a9889 646 debugs(50, 6, "getMyHostname: '" << host << "' has rDNS.");
cc192b50 647 present = 1;
648
649 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
26ac0430 650 if (AI) {
cc192b50 651 xfreeaddrinfo(AI);
652 AI = NULL;
653 }
62e76326 654
cc192b50 655 return host;
656 }
657
26ac0430 658 if (AI) xfreeaddrinfo(AI);
626a9889 659 debugs(50, 1, "WARNING: '" << host << "' rDNS test failed: " << xstrerror());
cc192b50 660 }
44a47c6e 661 }
62e76326 662
cc192b50 663 /* throw a fatal configuration error when the Host/IP given has bad DNS/rDNS. */
a572d8be 664 if (opt_send_signal == -1)
665 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
666 else
667 return ("localhost");
668
d20b1cd0 669 return NULL; /* keep compiler happy */
44a47c6e 670}
671
98829f69 672const char *
673uniqueHostname(void)
674{
23c6ebc4 675 debugs(21, 3, HERE << " Config: '" << Config.uniqueHostname << "'");
98829f69 676 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
677}
678
23c6ebc4 679/** leave a priviliged section. (Give up any privilegies)
30a4f2a8 680 * Routines that need privilegies can rap themselves in enter_suid()
681 * and leave_suid()
682 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 683 */
b8d8561b 684void
0673c0ba 685leave_suid(void)
12b9e9b1 686{
36584579 687 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
62e76326 688
e3d74828 689 if (Config.effectiveGroup) {
690
691#if HAVE_SETGROUPS
692
693 setgroups(1, &Config2.effectiveGroupID);
694
695#endif
696
697 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 698 debugs(50, 0, "ALERT: setgid: " << xstrerror());
e3d74828 699
700 }
701
12b9e9b1 702 if (geteuid() != 0)
62e76326 703 return;
704
12b9e9b1 705 /* Started as a root, check suid option */
b6f794d6 706 if (Config.effectiveUser == NULL)
62e76326 707 return;
708
36584579 709 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
62e76326 710
e3d74828 711 if (!Config.effectiveGroup) {
62e76326 712
e3d74828 713 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 714 debugs(50, 0, "ALERT: setgid: " << xstrerror());
62e76326 715
e3d74828 716 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
bf8fe701 717 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
718 Config.effectiveUser << " and Group " <<
719 (unsigned) Config2.effectiveGroupID << "");
e3d74828 720 }
721 }
62e76326 722
234967c9 723#if HAVE_SETRESUID
62e76326 724
d20b1cd0 725 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
bf8fe701 726 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
62e76326 727
234967c9 728#elif HAVE_SETEUID
62e76326 729
d20b1cd0 730 if (seteuid(Config2.effectiveUserID) < 0)
bf8fe701 731 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
62e76326 732
234967c9 733#else
62e76326 734
d20b1cd0 735 if (setuid(Config2.effectiveUserID) < 0)
bf8fe701 736 debugs(50, 0, "ALERT: setuid: " << xstrerror());
62e76326 737
fc68f6b1 738#endif
fc68f6b1 739
329ce686 740 restoreCapabilities(1);
fc68f6b1 741
62ae0622 742#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
743 /* Set Linux DUMPABLE flag */
744 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 745 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 746
234967c9 747#endif
748}
749
30a4f2a8 750/* Enter a privilegied section */
b8d8561b 751void
0673c0ba 752enter_suid(void)
234967c9 753{
36584579 754 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
234967c9 755#if HAVE_SETRESUID
62e76326 756
e6ccf245 757 setresuid((uid_t)-1, 0, (uid_t)-1);
234967c9 758#else
62e76326 759
234967c9 760 setuid(0);
761#endif
62ae0622 762#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
763 /* Set Linux DUMPABLE flag */
764
765 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 766 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 767
768#endif
234967c9 769}
770
30a4f2a8 771/* Give up the posibility to gain privilegies.
772 * this should be used before starting a sub process
773 */
b8d8561b 774void
0673c0ba 775no_suid(void)
234967c9 776{
777 uid_t uid;
30a4f2a8 778 leave_suid();
234967c9 779 uid = geteuid();
329ce686 780 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
62e76326 781
234967c9 782 setuid(0);
62e76326 783
429fdbec 784 if (setuid(uid) < 0)
bf8fe701 785 debugs(50, 1, "no_suid: setuid: " << xstrerror());
62e76326 786
329ce686 787 restoreCapabilities(0);
788
62ae0622 789#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
790 /* Set Linux DUMPABLE flag */
791 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 792 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 793
234967c9 794#endif
12b9e9b1 795}
ccff9601 796
b8d8561b 797void
0673c0ba 798writePidFile(void)
ccff9601 799{
9e4ad609 800 int fd;
0b4639af 801 const char *f = NULL;
973e9fe1 802 mode_t old_umask;
9e4ad609 803 char buf[32];
62e76326 804
9e4ad609 805 if ((f = Config.pidFilename) == NULL)
62e76326 806 return;
807
9e4ad609 808 if (!strcmp(Config.pidFilename, "none"))
62e76326 809 return;
810
30a4f2a8 811 enter_suid();
62e76326 812
973e9fe1 813 old_umask = umask(022);
62e76326 814
c4aefe96 815 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT);
62e76326 816
973e9fe1 817 umask(old_umask);
62e76326 818
30a4f2a8 819 leave_suid();
62e76326 820
9e4ad609 821 if (fd < 0) {
bf8fe701 822 debugs(50, 0, "" << f << ": " << xstrerror());
62e76326 823 debug_trap("Could not write pid file");
824 return;
ccff9601 825 }
62e76326 826
56878878 827 snprintf(buf, 32, "%d\n", (int) getpid());
1f7c9178 828 FD_WRITE_METHOD(fd, buf, strlen(buf));
9e4ad609 829 file_close(fd);
ccff9601 830}
c4fb974e 831
832
ff8d0ea6 833pid_t
0673c0ba 834readPidFile(void)
7690e8eb 835{
836 FILE *pid_fp = NULL;
9e4ad609 837 const char *f = Config.pidFilename;
1ee742a2 838 char *chroot_f = NULL;
ff8d0ea6 839 pid_t pid = -1;
840 int i;
7690e8eb 841
9e4ad609 842 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7dbca7a4 843 fprintf(stderr, APP_SHORTNAME ": ERROR: No pid file name defined\n");
62e76326 844 exit(1);
7690e8eb 845 }
62e76326 846
1ee742a2 847 if (Config.chroot_dir && geteuid() == 0) {
848 int len = strlen(Config.chroot_dir) + 1 + strlen(f) + 1;
849 chroot_f = (char *)xmalloc(strlen(Config.chroot_dir) + 1 + strlen(f) + 1);
850 snprintf(chroot_f, len, "%s/%s", Config.chroot_dir, f);
851 f = chroot_f;
852 }
853
7690e8eb 854 pid_fp = fopen(f, "r");
62e76326 855
7690e8eb 856 if (pid_fp != NULL) {
62e76326 857 pid = 0;
858
859 if (fscanf(pid_fp, "%d", &i) == 1)
860 pid = (pid_t) i;
861
862 fclose(pid_fp);
7690e8eb 863 } else {
62e76326 864 if (errno != ENOENT) {
7dbca7a4 865 fprintf(stderr, APP_SHORTNAME ": ERROR: Could not read pid file\n");
62e76326 866 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
867 exit(1);
868 }
7690e8eb 869 }
62e76326 870
1ee742a2 871 safe_free(chroot_f);
7690e8eb 872 return pid;
873}
874
875
b8d8561b 876void
0673c0ba 877setMaxFD(void)
c4fb974e 878{
234967c9 879#if HAVE_SETRLIMIT
c4fb974e 880 /* try to use as many file descriptors as possible */
881 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
62e76326 882
c4fb974e 883 struct rlimit rl;
884#if defined(RLIMIT_NOFILE)
62e76326 885
c4fb974e 886 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
bf8fe701 887 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 888 } else {
62e76326 889 rl.rlim_cur = Squid_MaxFD;
890
891 if (rl.rlim_cur > rl.rlim_max)
892 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
893
894 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
895 snprintf(tmp_error_buf, ERROR_BUF_SZ,
896 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
897 fatal_dump(tmp_error_buf);
898 }
c4fb974e 899 }
62e76326 900
c4fb974e 901#elif defined(RLIMIT_OFILE)
902 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
bf8fe701 903 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 904 } else {
62e76326 905 rl.rlim_cur = Squid_MaxFD;
906
907 if (rl.rlim_cur > rl.rlim_max)
908 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
909
910 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
911 snprintf(tmp_error_buf, ERROR_BUF_SZ,
912 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
913 fatal_dump(tmp_error_buf);
914 }
c4fb974e 915 }
62e76326 916
c4fb974e 917#endif
c4fb974e 918#else /* HAVE_SETRLIMIT */
bf8fe701 919 debugs(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
62e76326 920
30a4f2a8 921#endif /* HAVE_SETRLIMIT */
922
923#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
62e76326 924
30a4f2a8 925 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
bf8fe701 926 debugs(50, 0, "getrlimit: RLIMIT_DATA: " << xstrerror());
88738790 927 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 928 rl.rlim_cur = rl.rlim_max; /* set it to the max */
929
930 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
931 snprintf(tmp_error_buf, ERROR_BUF_SZ,
932 "setrlimit: RLIMIT_DATA: %s", xstrerror());
933 fatal_dump(tmp_error_buf);
934 }
30a4f2a8 935 }
62e76326 936
30a4f2a8 937#endif /* RLIMIT_DATA */
ad7ef91a 938#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
939 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
bf8fe701 940 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
88738790 941 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 942 rl.rlim_cur = rl.rlim_max; /* set it to the max */
943
944 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
945 snprintf(tmp_error_buf, ERROR_BUF_SZ,
946 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
947 fatal_dump(tmp_error_buf);
948 }
ad7ef91a 949 }
62e76326 950
ad7ef91a 951#endif /* RLIMIT_VMEM */
c4fb974e 952}
3a57089e 953
b8d8561b 954int
955percent(int a, int b)
30a4f2a8 956{
957 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
958}
959
a7c05555 960double
f2908497 961dpercent(double a, double b)
962{
963 return b ? (100.0 * a / b) : 0.0;
964}
965
b8d8561b 966void
ea3a2a69 967squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 968{
969#if HAVE_SIGACTION
62e76326 970
30a4f2a8 971 struct sigaction sa;
972 sa.sa_handler = func;
973 sa.sa_flags = flags;
974 sigemptyset(&sa.sa_mask);
62e76326 975
30a4f2a8 976 if (sigaction(sig, &sa, NULL) < 0)
bf8fe701 977 debugs(50, 0, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerror());
62e76326 978
30a4f2a8 979#else
06648839 980#ifdef _SQUID_MSWIN_
981 /*
982 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
983 are supported, so we must care of don't call signal() for other value.
984 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
985 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
986 */
987 switch (sig) {
988
989 case SIGINT:
990
991 case SIGILL:
992
993 case SIGFPE:
994
995 case SIGTERM:
996
997 case SIGBREAK:
998
999 case SIGABRT:
1000 break;
1001
1002 case SIGSEGV:
1003 WIN32_ExceptionHandlerInit();
1004 break;
1005
1006 case SIGBUS:
1007 WIN32_ExceptionHandlerInit();
1008 return;
1009 break; /* Nor reached */
1010
1011 default:
1012 return;
1013 break; /* Nor reached */
1014 }
1015
1016#endif
62e76326 1017
06648839 1018 signal(sig, func);
62e76326 1019
30a4f2a8 1020#endif
1021}
396c5745 1022
9e4ad609 1023double
e6ccf245 1024doubleAverage(double cur, double newD, int N, int max)
9e4ad609 1025{
1d8e0d40 1026 if (N > max)
62e76326 1027 N = max;
1028
e6ccf245 1029 return (cur * (N - 1.0) + newD) / N;
9e4ad609 1030}
1031
1032int
e6ccf245 1033intAverage(int cur, int newI, int n, int max)
9e4ad609 1034{
1035 if (n > max)
62e76326 1036 n = max;
1037
e6ccf245 1038 return (cur * (n - 1) + newI) / n;
9e4ad609 1039}
70364f29 1040
1041void
1042logsFlush(void)
1043{
1044 if (debug_log)
62e76326 1045 fflush(debug_log);
70364f29 1046}
88738790 1047
16300b58 1048void
0e473d70 1049kb_incr(kb_t * k, size_t v)
a7c05555 1050{
0e473d70 1051 k->bytes += v;
1052 k->kb += (k->bytes >> 10);
1053 k->bytes &= 0x3FF;
a7c05555 1054}
c1dabf04 1055
a00a7c85 1056void
6bbf9cc4 1057debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 1058{
1059 MemBuf mb;
1060 Packer p;
6bbf9cc4 1061 assert(label && obj && pm);
2fe7eff9 1062 mb.init();
a00a7c85 1063 packerToMemInit(&p, &mb);
0cdcddb9 1064 (*pm) (obj, &p);
bf8fe701 1065 debugs(section, level, "" << label << "" << mb.buf << "");
a00a7c85 1066 packerClean(&p);
2fe7eff9 1067 mb.clean();
a00a7c85 1068}
d548ee64 1069
0e70aa1e 1070void
1071parseEtcHosts(void)
1072{
1073 FILE *fp;
1074 char buf[1024];
1075 char buf2[512];
1076 char *nt = buf;
1077 char *lt = buf;
fa2bfbab 1078
0e70aa1e 1079 if (NULL == Config.etcHostsPath)
62e76326 1080 return;
1081
0e70aa1e 1082 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 1083 return;
1084
0e70aa1e 1085 fp = fopen(Config.etcHostsPath, "r");
62e76326 1086
0e70aa1e 1087 if (fp == NULL) {
bf8fe701 1088 debugs(1, 1, "parseEtcHosts: " << Config.etcHostsPath << ": " << xstrerror());
62e76326 1089 return;
0e70aa1e 1090 }
62e76326 1091
ec4daaa5 1092#ifdef _SQUID_WIN32_
c4aefe96 1093 setmode(fileno(fp), O_TEXT);
62e76326 1094
c4aefe96 1095#endif
62e76326 1096
0e70aa1e 1097 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1098 wordlist *hosts = NULL;
1099 char *addr;
1100
c31616ae 1101 if (buf[0] == '#') /* MS-windows likes to add comments */
1102 continue;
1103
7a10c315 1104 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1105
1106 lt = buf;
1107
1108 addr = buf;
1109
bf8fe701 1110 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
62e76326 1111
1112 nt = strpbrk(lt, w_space);
1113
1114 if (nt == NULL) /* empty line */
1115 continue;
1116
1117 *nt = '\0'; /* null-terminate the address */
1118
bf8fe701 1119 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
62e76326 1120
1121 lt = nt + 1;
1122
1123 while ((nt = strpbrk(lt, w_space))) {
1124 char *host = NULL;
1125
1126 if (nt == lt) { /* multiple spaces */
bf8fe701 1127 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
62e76326 1128 lt = nt + 1;
1129 continue;
1130 }
1131
1132 *nt = '\0';
bf8fe701 1133 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
62e76326 1134
1135 if (Config.appendDomain && !strchr(lt, '.')) {
1136 /* I know it's ugly, but it's only at reconfig */
1137 strncpy(buf2, lt, 512);
3fbd26b5 1138 strncat(buf2, Config.appendDomain, 512 - strlen(lt) - 1);
62e76326 1139 host = buf2;
1140 } else {
1141 host = lt;
1142 }
1143
f6a72b33
AJ
1144 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1145 /* invalid address, continuing is useless */
1146 wordlistDestroy(&hosts);
1147 hosts = NULL;
1148 break;
1149 }
62e76326 1150 wordlistAdd(&hosts, host);
1151
1152 lt = nt + 1;
1153 }
1154
9e008dda 1155 if (hosts) {
f6a72b33
AJ
1156 fqdncacheAddEntryFromHosts(addr, hosts);
1157 wordlistDestroy(&hosts);
1158 }
0e70aa1e 1159 }
62e76326 1160
1f3c7397 1161 fclose (fp);
0e70aa1e 1162}
52f772de 1163
1164int
1165getMyPort(void)
1166{
52f772de 1167 if (Config.Sockaddr.http)
cc192b50 1168 return Config.Sockaddr.http->s.GetPort();
62e76326 1169
a2727cdb 1170#if USE_SSL
62e76326 1171
a2727cdb 1172 if (Config.Sockaddr.https)
cc192b50 1173 return Config.Sockaddr.https->http.s.GetPort();
62e76326 1174
52f772de 1175#endif
62e76326 1176
a2727cdb 1177 fatal("No port defined");
62e76326 1178
bac6d4bd 1179 return 0; /* NOT REACHED */
52f772de 1180}
d860a1aa 1181
c642c141
AJ
1182/*
1183 * Set the umask to at least the given mask. This is in addition
1184 * to the umask set at startup
1185 */
1186void
1187setUmask(mode_t mask)
1188{
1189 // No way to get the current umask value without setting it.
1190 static const mode_t orig_umask = umask(mask); // once, to get
1191 umask(mask | orig_umask); // always, to set
1192}
d860a1aa 1193
1194/*
1195 * Inverse of strwordtok. Quotes a word if needed
1196 */
42419a95 1197void
d860a1aa 1198strwordquote(MemBuf * mb, const char *str)
1199{
1200 int quoted = 0;
62e76326 1201
d860a1aa 1202 if (strchr(str, ' ')) {
62e76326 1203 quoted = 1;
2fe7eff9 1204 mb->append("\"", 1);
d860a1aa 1205 }
62e76326 1206
d860a1aa 1207 while (*str) {
dc1af3cf 1208 int l = strcspn(str, "\"\\\n\r");
2fe7eff9 1209 mb->append(str, l);
62e76326 1210 str += l;
1211
26ac0430 1212 switch (*str) {
dc1af3cf 1213
1214 case '\n':
2fe7eff9 1215 mb->append("\\n", 2);
dc1af3cf 1216 str++;
1217 break;
1218
1219 case '\r':
2fe7eff9 1220 mb->append("\\r", 2);
dc1af3cf 1221 str++;
1222 break;
1223
1224 case '\0':
1225 break;
1226
1227 default:
2fe7eff9 1228 mb->append("\\", 1);
1229 mb->append(str, 1);
62e76326 1230 str++;
dc1af3cf 1231 break;
62e76326 1232 }
d860a1aa 1233 }
62e76326 1234
d860a1aa 1235 if (quoted)
2fe7eff9 1236 mb->append("\"", 1);
d860a1aa 1237}
fc68f6b1 1238
1239void
1240keepCapabilities(void)
1241{
329ce686 1242#if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && HAVE_SYS_CAPABILITY_H
1243
1244 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
85944c1c 1245 IpInterceptor.StopTransparency("capability setting has failed.");
fc68f6b1 1246 }
fc68f6b1 1247#endif
1248}
329ce686 1249
1250static void
1251restoreCapabilities(int keep)
1252{
9e008dda 1253 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
b5bd96ce
AJ
1254#if defined(_SQUID_LINUX_)
1255
1256#if HAVE_SYS_CAPABILITY_H
b5f9c580
HN
1257#ifndef _LINUX_CAPABILITY_VERSION_1
1258#define _LINUX_CAPABILITY_VERSION_1 _LINUX_CAPABILITY_VERSION
1259#endif
fd3cc4b6
HN
1260 cap_user_header_t head = (cap_user_header_t) xcalloc(1, sizeof(*head));
1261 cap_user_data_t cap = (cap_user_data_t) xcalloc(1, sizeof(*cap));
329ce686 1262
92a9a48d 1263 head->version = _LINUX_CAPABILITY_VERSION_1;
329ce686 1264
1265 if (capget(head, cap) != 0) {
b5bd96ce 1266 debugs(50, DBG_IMPORTANT, "Can't get current capabilities");
9e008dda 1267 } else if (head->version != _LINUX_CAPABILITY_VERSION_1) {
b5bd96ce 1268 debugs(50, DBG_IMPORTANT, "Invalid capability version " << head->version << " (expected " << _LINUX_CAPABILITY_VERSION_1 << ")");
9e008dda 1269 } else {
329ce686 1270
b5bd96ce 1271 head->pid = 0;
329ce686 1272
b5bd96ce
AJ
1273 cap->inheritable = 0;
1274 cap->effective = (1 << CAP_NET_BIND_SERVICE);
329ce686 1275
85944c1c 1276 if (IpInterceptor.TransparentActive()) {
b5bd96ce 1277 cap->effective |= (1 << CAP_NET_ADMIN);
04f87469 1278#if LINUX_TPROXY2
b5bd96ce 1279 cap->effective |= (1 << CAP_NET_BROADCAST);
329ce686 1280#endif
b5bd96ce 1281 }
329ce686 1282
b5bd96ce
AJ
1283 if (!keep)
1284 cap->permitted &= cap->effective;
329ce686 1285
b5bd96ce 1286 if (capset(head, cap) != 0) {
85944c1c 1287 IpInterceptor.StopTransparency("Error enabling needed capabilities.");
b5bd96ce 1288 }
329ce686 1289 }
1290
329ce686 1291 xfree(head);
1292 xfree(cap);
329ce686 1293
b5bd96ce 1294#else
85944c1c 1295 IpInterceptor.StopTransparency("Missing needed capability support.");
b5bd96ce
AJ
1296#endif /* HAVE_SYS_CAPABILITY_H */
1297
1298#endif /* !defined(_SQUID_LINUX_) */
329ce686 1299}
cc192b50 1300
1301void *
1302xmemset(void *dst, int val, size_t sz)
1303{
1304 // do debugs output
1305 debugs(63, 9, "memset: dst=" << dst << ", val=" << val << ", bytes=" << sz);
1306
1307 // call the system one to do the actual work ~safely.
1308 return memset(dst, val, sz);
1309}