]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Better error reporting and detection for kqueue support
[thirdparty/squid.git] / src / tools.cc
CommitLineData
30a4f2a8 1/*
07f765a3 2 * $Id: tools.cc,v 1.281 2008/02/11 22:44:50 rousskov Exp $
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"
04f87469 42#include "IPInterception.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 */
6de2df60 496#if STDC_HEADERS
137ee196 497void
498fatalf(const char *fmt,...)
499{
500 va_list args;
501 va_start(args, fmt);
502#else
503void
504fatalf(va_alist)
26ac0430 505va_dcl {
137ee196 506 va_list args;
507 const char *fmt = NULL;
508 va_start(args);
509 fmt = va_arg(args, char *);
510#endif
62e76326 511
137ee196 512 fatalvf(fmt, args);
513 va_end(args);
514}
515
516
517/* used by fatalf */
518static void
62e76326 519fatalvf(const char *fmt, va_list args) {
137ee196 520 static char fatal_str[BUFSIZ];
521 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
522 fatal(fatal_str);
523}
524
090089c4 525/* fatal with dumping core */
b8d8561b 526void
62e76326 527fatal_dump(const char *message) {
7e3ce7b9 528 failure_notify = NULL;
429fdbec 529 releaseServerSockets();
62e76326 530
090089c4 531 if (message)
62e76326 532 fatal_common(message);
533
776ff02c 534 /*
535 * Call leave_suid() here to make sure that swap.state files
536 * are written as the effective user, rather than root. Squid
537 * may take on root privs during reconfigure. If squid.conf
538 * contains a "Bungled" line, fatal() will be called when the
539 * process still has root privs.
540 */
541 leave_suid();
542
4a69c163 543 if (opt_catch_signals)
62e76326 544 storeDirWriteCleanLogs(0);
545
090089c4 546 abort();
547}
548
b8d8561b 549void
62e76326 550debug_trap(const char *message) {
4a69c163 551 if (!opt_catch_signals)
62e76326 552 fatal_dump(message);
553
a3d5953d 554 _db_print("WARNING: %s\n", message);
85b701ed 555}
556
b8d8561b 557void
62e76326 558sig_child(int sig) {
a50bfe93 559#ifndef _SQUID_MSWIN_
30a4f2a8 560#ifdef _SQUID_NEXT_
561 union wait status;
562#else
62e76326 563
090089c4 564 int status;
090089c4 565#endif
62e76326 566
ff8d0ea6 567 pid_t pid;
090089c4 568
30a4f2a8 569 do {
570#ifdef _SQUID_NEXT_
62e76326 571 pid = wait3(&status, WNOHANG, NULL);
090089c4 572#else
62e76326 573
574 pid = waitpid(-1, &status, WNOHANG);
090089c4 575#endif
62e76326 576 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 577#if HAVE_SIGACTION
62e76326 578
30a4f2a8 579 } while (pid > 0);
62e76326 580
234967c9 581#else
62e76326 582
583 }
584
3d0ac046 585 while (pid > 0 || (pid < 0 && errno == EINTR));
30a4f2a8 586 signal(sig, sig_child);
62e76326 587
a50bfe93 588#endif
234967c9 589#endif
30a4f2a8 590}
44a47c6e 591
0ee4272b 592const char *
0673c0ba 593getMyHostname(void)
44a47c6e 594{
95d659f0 595 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 596 static int present = 0;
cc192b50 597 struct addrinfo *AI = NULL;
598 IPAddress sa;
62e76326 599
af85f811 600 if (Config.visibleHostname != NULL)
62e76326 601 return Config.visibleHostname;
602
d20b1cd0 603 if (present)
62e76326 604 return host;
605
d20b1cd0 606 host[0] = '\0';
62e76326 607
cc192b50 608 if (Config.Sockaddr.http && sa.IsAnyAddr())
609 sa = Config.Sockaddr.http->s;
62e76326 610
aa2b5399 611#if USE_SSL
62e76326 612
cc192b50 613 if (Config.Sockaddr.https && sa.IsAnyAddr())
614 sa = Config.Sockaddr.https->http.s;
62e76326 615
aa2b5399 616#endif
cc192b50 617
aa2b5399 618 /*
619 * If the first http_port address has a specific address, try a
620 * reverse DNS lookup on it.
621 */
26ac0430 622 if ( !sa.IsAnyAddr() ) {
62e76326 623
cc192b50 624 sa.GetAddrInfo(AI);
625 /* we are looking for a name. */
26ac0430 626 if (xgetnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, NULL, 0, NI_NAMEREQD ) == 0) {
62e76326 627 /* DNS lookup successful */
628 /* use the official name from DNS lookup */
cc192b50 629 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
bf8fe701 630
62e76326 631 present = 1;
632
cc192b50 633 sa.FreeAddrInfo(AI);
634
62e76326 635 if (strchr(host, '.'))
636 return host;
62e76326 637 }
638
cc192b50 639 sa.FreeAddrInfo(AI);
640 debugs(50, 1, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
26ac0430 641 } else {
cc192b50 642 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
643 debugs(50, 1, "WARNING: gethostname failed: " << xstrerror());
26ac0430 644 } else {
cc192b50 645 /* Verify that the hostname given resolves properly */
646 struct addrinfo hints;
647 memset(&hints, 0, sizeof(addrinfo));
648 hints.ai_flags = AI_CANONNAME;
649
26ac0430 650 if (xgetaddrinfo(host, NULL, NULL, &AI) == 0) {
cc192b50 651 /* DNS lookup successful */
652 /* use the official name from DNS lookup */
626a9889 653 debugs(50, 6, "getMyHostname: '" << host << "' has rDNS.");
cc192b50 654 present = 1;
655
656 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
26ac0430 657 if (AI) {
cc192b50 658 xfreeaddrinfo(AI);
659 AI = NULL;
660 }
62e76326 661
cc192b50 662 return host;
663 }
664
26ac0430 665 if (AI) xfreeaddrinfo(AI);
626a9889 666 debugs(50, 1, "WARNING: '" << host << "' rDNS test failed: " << xstrerror());
cc192b50 667 }
44a47c6e 668 }
62e76326 669
cc192b50 670 /* throw a fatal configuration error when the Host/IP given has bad DNS/rDNS. */
a572d8be 671 if (opt_send_signal == -1)
672 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
673 else
674 return ("localhost");
675
d20b1cd0 676 return NULL; /* keep compiler happy */
44a47c6e 677}
678
98829f69 679const char *
680uniqueHostname(void)
681{
23c6ebc4 682 debugs(21, 3, HERE << " Config: '" << Config.uniqueHostname << "'");
98829f69 683 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
684}
685
23c6ebc4 686/** leave a priviliged section. (Give up any privilegies)
30a4f2a8 687 * Routines that need privilegies can rap themselves in enter_suid()
688 * and leave_suid()
689 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 690 */
b8d8561b 691void
0673c0ba 692leave_suid(void)
12b9e9b1 693{
36584579 694 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
62e76326 695
e3d74828 696 if (Config.effectiveGroup) {
697
698#if HAVE_SETGROUPS
699
700 setgroups(1, &Config2.effectiveGroupID);
701
702#endif
703
704 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 705 debugs(50, 0, "ALERT: setgid: " << xstrerror());
e3d74828 706
707 }
708
12b9e9b1 709 if (geteuid() != 0)
62e76326 710 return;
711
12b9e9b1 712 /* Started as a root, check suid option */
b6f794d6 713 if (Config.effectiveUser == NULL)
62e76326 714 return;
715
36584579 716 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
62e76326 717
e3d74828 718 if (!Config.effectiveGroup) {
62e76326 719
e3d74828 720 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 721 debugs(50, 0, "ALERT: setgid: " << xstrerror());
62e76326 722
e3d74828 723 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
bf8fe701 724 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
725 Config.effectiveUser << " and Group " <<
726 (unsigned) Config2.effectiveGroupID << "");
e3d74828 727 }
728 }
62e76326 729
234967c9 730#if HAVE_SETRESUID
62e76326 731
d20b1cd0 732 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
bf8fe701 733 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
62e76326 734
234967c9 735#elif HAVE_SETEUID
62e76326 736
d20b1cd0 737 if (seteuid(Config2.effectiveUserID) < 0)
bf8fe701 738 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
62e76326 739
234967c9 740#else
62e76326 741
d20b1cd0 742 if (setuid(Config2.effectiveUserID) < 0)
bf8fe701 743 debugs(50, 0, "ALERT: setuid: " << xstrerror());
62e76326 744
fc68f6b1 745#endif
fc68f6b1 746
329ce686 747 restoreCapabilities(1);
fc68f6b1 748
62ae0622 749#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
750 /* Set Linux DUMPABLE flag */
751 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 752 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 753
234967c9 754#endif
755}
756
30a4f2a8 757/* Enter a privilegied section */
b8d8561b 758void
0673c0ba 759enter_suid(void)
234967c9 760{
36584579 761 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
234967c9 762#if HAVE_SETRESUID
62e76326 763
e6ccf245 764 setresuid((uid_t)-1, 0, (uid_t)-1);
234967c9 765#else
62e76326 766
234967c9 767 setuid(0);
768#endif
62ae0622 769#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
770 /* Set Linux DUMPABLE flag */
771
772 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 773 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 774
775#endif
234967c9 776}
777
30a4f2a8 778/* Give up the posibility to gain privilegies.
779 * this should be used before starting a sub process
780 */
b8d8561b 781void
0673c0ba 782no_suid(void)
234967c9 783{
784 uid_t uid;
30a4f2a8 785 leave_suid();
234967c9 786 uid = geteuid();
329ce686 787 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
62e76326 788
234967c9 789 setuid(0);
62e76326 790
429fdbec 791 if (setuid(uid) < 0)
bf8fe701 792 debugs(50, 1, "no_suid: setuid: " << xstrerror());
62e76326 793
329ce686 794 restoreCapabilities(0);
795
62ae0622 796#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
797 /* Set Linux DUMPABLE flag */
798 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 799 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 800
234967c9 801#endif
12b9e9b1 802}
ccff9601 803
b8d8561b 804void
0673c0ba 805writePidFile(void)
ccff9601 806{
9e4ad609 807 int fd;
0b4639af 808 const char *f = NULL;
973e9fe1 809 mode_t old_umask;
9e4ad609 810 char buf[32];
62e76326 811
9e4ad609 812 if ((f = Config.pidFilename) == NULL)
62e76326 813 return;
814
9e4ad609 815 if (!strcmp(Config.pidFilename, "none"))
62e76326 816 return;
817
30a4f2a8 818 enter_suid();
62e76326 819
973e9fe1 820 old_umask = umask(022);
62e76326 821
c4aefe96 822 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT);
62e76326 823
973e9fe1 824 umask(old_umask);
62e76326 825
30a4f2a8 826 leave_suid();
62e76326 827
9e4ad609 828 if (fd < 0) {
bf8fe701 829 debugs(50, 0, "" << f << ": " << xstrerror());
62e76326 830 debug_trap("Could not write pid file");
831 return;
ccff9601 832 }
62e76326 833
56878878 834 snprintf(buf, 32, "%d\n", (int) getpid());
1f7c9178 835 FD_WRITE_METHOD(fd, buf, strlen(buf));
9e4ad609 836 file_close(fd);
ccff9601 837}
c4fb974e 838
839
ff8d0ea6 840pid_t
0673c0ba 841readPidFile(void)
7690e8eb 842{
843 FILE *pid_fp = NULL;
9e4ad609 844 const char *f = Config.pidFilename;
1ee742a2 845 char *chroot_f = NULL;
ff8d0ea6 846 pid_t pid = -1;
847 int i;
7690e8eb 848
9e4ad609 849 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7dbca7a4 850 fprintf(stderr, APP_SHORTNAME ": ERROR: No pid file name defined\n");
62e76326 851 exit(1);
7690e8eb 852 }
62e76326 853
1ee742a2 854 if (Config.chroot_dir && geteuid() == 0) {
855 int len = strlen(Config.chroot_dir) + 1 + strlen(f) + 1;
856 chroot_f = (char *)xmalloc(strlen(Config.chroot_dir) + 1 + strlen(f) + 1);
857 snprintf(chroot_f, len, "%s/%s", Config.chroot_dir, f);
858 f = chroot_f;
859 }
860
7690e8eb 861 pid_fp = fopen(f, "r");
62e76326 862
7690e8eb 863 if (pid_fp != NULL) {
62e76326 864 pid = 0;
865
866 if (fscanf(pid_fp, "%d", &i) == 1)
867 pid = (pid_t) i;
868
869 fclose(pid_fp);
7690e8eb 870 } else {
62e76326 871 if (errno != ENOENT) {
7dbca7a4 872 fprintf(stderr, APP_SHORTNAME ": ERROR: Could not read pid file\n");
62e76326 873 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
874 exit(1);
875 }
7690e8eb 876 }
62e76326 877
1ee742a2 878 safe_free(chroot_f);
7690e8eb 879 return pid;
880}
881
882
b8d8561b 883void
0673c0ba 884setMaxFD(void)
c4fb974e 885{
234967c9 886#if HAVE_SETRLIMIT
c4fb974e 887 /* try to use as many file descriptors as possible */
888 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
62e76326 889
c4fb974e 890 struct rlimit rl;
891#if defined(RLIMIT_NOFILE)
62e76326 892
c4fb974e 893 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
bf8fe701 894 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 895 } else {
62e76326 896 rl.rlim_cur = Squid_MaxFD;
897
898 if (rl.rlim_cur > rl.rlim_max)
899 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
900
901 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
902 snprintf(tmp_error_buf, ERROR_BUF_SZ,
903 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
904 fatal_dump(tmp_error_buf);
905 }
c4fb974e 906 }
62e76326 907
c4fb974e 908#elif defined(RLIMIT_OFILE)
909 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
bf8fe701 910 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 911 } else {
62e76326 912 rl.rlim_cur = Squid_MaxFD;
913
914 if (rl.rlim_cur > rl.rlim_max)
915 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
916
917 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
918 snprintf(tmp_error_buf, ERROR_BUF_SZ,
919 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
920 fatal_dump(tmp_error_buf);
921 }
c4fb974e 922 }
62e76326 923
c4fb974e 924#endif
c4fb974e 925#else /* HAVE_SETRLIMIT */
bf8fe701 926 debugs(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
62e76326 927
30a4f2a8 928#endif /* HAVE_SETRLIMIT */
929
930#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
62e76326 931
30a4f2a8 932 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
bf8fe701 933 debugs(50, 0, "getrlimit: RLIMIT_DATA: " << xstrerror());
88738790 934 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 935 rl.rlim_cur = rl.rlim_max; /* set it to the max */
936
937 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
938 snprintf(tmp_error_buf, ERROR_BUF_SZ,
939 "setrlimit: RLIMIT_DATA: %s", xstrerror());
940 fatal_dump(tmp_error_buf);
941 }
30a4f2a8 942 }
62e76326 943
30a4f2a8 944#endif /* RLIMIT_DATA */
ad7ef91a 945#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
946 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
bf8fe701 947 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
88738790 948 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 949 rl.rlim_cur = rl.rlim_max; /* set it to the max */
950
951 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
952 snprintf(tmp_error_buf, ERROR_BUF_SZ,
953 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
954 fatal_dump(tmp_error_buf);
955 }
ad7ef91a 956 }
62e76326 957
ad7ef91a 958#endif /* RLIMIT_VMEM */
c4fb974e 959}
3a57089e 960
b8d8561b 961int
962percent(int a, int b)
30a4f2a8 963{
964 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
965}
966
a7c05555 967double
f2908497 968dpercent(double a, double b)
969{
970 return b ? (100.0 * a / b) : 0.0;
971}
972
b8d8561b 973void
ea3a2a69 974squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 975{
976#if HAVE_SIGACTION
62e76326 977
30a4f2a8 978 struct sigaction sa;
979 sa.sa_handler = func;
980 sa.sa_flags = flags;
981 sigemptyset(&sa.sa_mask);
62e76326 982
30a4f2a8 983 if (sigaction(sig, &sa, NULL) < 0)
bf8fe701 984 debugs(50, 0, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerror());
62e76326 985
30a4f2a8 986#else
06648839 987#ifdef _SQUID_MSWIN_
988 /*
989 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
990 are supported, so we must care of don't call signal() for other value.
991 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
992 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
993 */
994 switch (sig) {
995
996 case SIGINT:
997
998 case SIGILL:
999
1000 case SIGFPE:
1001
1002 case SIGTERM:
1003
1004 case SIGBREAK:
1005
1006 case SIGABRT:
1007 break;
1008
1009 case SIGSEGV:
1010 WIN32_ExceptionHandlerInit();
1011 break;
1012
1013 case SIGBUS:
1014 WIN32_ExceptionHandlerInit();
1015 return;
1016 break; /* Nor reached */
1017
1018 default:
1019 return;
1020 break; /* Nor reached */
1021 }
1022
1023#endif
62e76326 1024
06648839 1025 signal(sig, func);
62e76326 1026
30a4f2a8 1027#endif
1028}
396c5745 1029
9e4ad609 1030double
e6ccf245 1031doubleAverage(double cur, double newD, int N, int max)
9e4ad609 1032{
1d8e0d40 1033 if (N > max)
62e76326 1034 N = max;
1035
e6ccf245 1036 return (cur * (N - 1.0) + newD) / N;
9e4ad609 1037}
1038
1039int
e6ccf245 1040intAverage(int cur, int newI, int n, int max)
9e4ad609 1041{
1042 if (n > max)
62e76326 1043 n = max;
1044
e6ccf245 1045 return (cur * (n - 1) + newI) / n;
9e4ad609 1046}
70364f29 1047
1048void
1049logsFlush(void)
1050{
1051 if (debug_log)
62e76326 1052 fflush(debug_log);
70364f29 1053}
88738790 1054
16300b58 1055void
0e473d70 1056kb_incr(kb_t * k, size_t v)
a7c05555 1057{
0e473d70 1058 k->bytes += v;
1059 k->kb += (k->bytes >> 10);
1060 k->bytes &= 0x3FF;
a7c05555 1061}
c1dabf04 1062
a00a7c85 1063void
6bbf9cc4 1064debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 1065{
1066 MemBuf mb;
1067 Packer p;
6bbf9cc4 1068 assert(label && obj && pm);
2fe7eff9 1069 mb.init();
a00a7c85 1070 packerToMemInit(&p, &mb);
0cdcddb9 1071 (*pm) (obj, &p);
bf8fe701 1072 debugs(section, level, "" << label << "" << mb.buf << "");
a00a7c85 1073 packerClean(&p);
2fe7eff9 1074 mb.clean();
a00a7c85 1075}
d548ee64 1076
0e70aa1e 1077void
1078parseEtcHosts(void)
1079{
1080 FILE *fp;
1081 char buf[1024];
1082 char buf2[512];
1083 char *nt = buf;
1084 char *lt = buf;
fa2bfbab 1085
0e70aa1e 1086 if (NULL == Config.etcHostsPath)
62e76326 1087 return;
1088
0e70aa1e 1089 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 1090 return;
1091
0e70aa1e 1092 fp = fopen(Config.etcHostsPath, "r");
62e76326 1093
0e70aa1e 1094 if (fp == NULL) {
bf8fe701 1095 debugs(1, 1, "parseEtcHosts: " << Config.etcHostsPath << ": " << xstrerror());
62e76326 1096 return;
0e70aa1e 1097 }
62e76326 1098
ec4daaa5 1099#ifdef _SQUID_WIN32_
c4aefe96 1100 setmode(fileno(fp), O_TEXT);
62e76326 1101
c4aefe96 1102#endif
62e76326 1103
0e70aa1e 1104 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1105 wordlist *hosts = NULL;
1106 char *addr;
1107
c31616ae 1108 if (buf[0] == '#') /* MS-windows likes to add comments */
1109 continue;
1110
7a10c315 1111 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1112
1113 lt = buf;
1114
1115 addr = buf;
1116
bf8fe701 1117 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
62e76326 1118
1119 nt = strpbrk(lt, w_space);
1120
1121 if (nt == NULL) /* empty line */
1122 continue;
1123
1124 *nt = '\0'; /* null-terminate the address */
1125
bf8fe701 1126 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
62e76326 1127
1128 lt = nt + 1;
1129
1130 while ((nt = strpbrk(lt, w_space))) {
1131 char *host = NULL;
1132
1133 if (nt == lt) { /* multiple spaces */
bf8fe701 1134 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
62e76326 1135 lt = nt + 1;
1136 continue;
1137 }
1138
1139 *nt = '\0';
bf8fe701 1140 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
62e76326 1141
1142 if (Config.appendDomain && !strchr(lt, '.')) {
1143 /* I know it's ugly, but it's only at reconfig */
1144 strncpy(buf2, lt, 512);
3fbd26b5 1145 strncat(buf2, Config.appendDomain, 512 - strlen(lt) - 1);
62e76326 1146 host = buf2;
1147 } else {
1148 host = lt;
1149 }
1150
1151 if (ipcacheAddEntryFromHosts(host, addr) != 0)
1152 goto skip; /* invalid address, continuing is useless */
1153
1154 wordlistAdd(&hosts, host);
1155
1156 lt = nt + 1;
1157 }
1158
1159 fqdncacheAddEntryFromHosts(addr, hosts);
1160
1161skip:
1162 wordlistDestroy(&hosts);
0e70aa1e 1163 }
62e76326 1164
1f3c7397 1165 fclose (fp);
0e70aa1e 1166}
52f772de 1167
1168int
1169getMyPort(void)
1170{
52f772de 1171 if (Config.Sockaddr.http)
cc192b50 1172 return Config.Sockaddr.http->s.GetPort();
62e76326 1173
a2727cdb 1174#if USE_SSL
62e76326 1175
a2727cdb 1176 if (Config.Sockaddr.https)
cc192b50 1177 return Config.Sockaddr.https->http.s.GetPort();
62e76326 1178
52f772de 1179#endif
62e76326 1180
a2727cdb 1181 fatal("No port defined");
62e76326 1182
bac6d4bd 1183 return 0; /* NOT REACHED */
52f772de 1184}
d860a1aa 1185
c642c141
AJ
1186/*
1187 * Set the umask to at least the given mask. This is in addition
1188 * to the umask set at startup
1189 */
1190void
1191setUmask(mode_t mask)
1192{
1193 // No way to get the current umask value without setting it.
1194 static const mode_t orig_umask = umask(mask); // once, to get
1195 umask(mask | orig_umask); // always, to set
1196}
d860a1aa 1197
1198/*
1199 * Inverse of strwordtok. Quotes a word if needed
1200 */
42419a95 1201void
d860a1aa 1202strwordquote(MemBuf * mb, const char *str)
1203{
1204 int quoted = 0;
62e76326 1205
d860a1aa 1206 if (strchr(str, ' ')) {
62e76326 1207 quoted = 1;
2fe7eff9 1208 mb->append("\"", 1);
d860a1aa 1209 }
62e76326 1210
d860a1aa 1211 while (*str) {
dc1af3cf 1212 int l = strcspn(str, "\"\\\n\r");
2fe7eff9 1213 mb->append(str, l);
62e76326 1214 str += l;
1215
26ac0430 1216 switch (*str) {
dc1af3cf 1217
1218 case '\n':
2fe7eff9 1219 mb->append("\\n", 2);
dc1af3cf 1220 str++;
1221 break;
1222
1223 case '\r':
2fe7eff9 1224 mb->append("\\r", 2);
dc1af3cf 1225 str++;
1226 break;
1227
1228 case '\0':
1229 break;
1230
1231 default:
2fe7eff9 1232 mb->append("\\", 1);
1233 mb->append(str, 1);
62e76326 1234 str++;
dc1af3cf 1235 break;
62e76326 1236 }
d860a1aa 1237 }
62e76326 1238
d860a1aa 1239 if (quoted)
2fe7eff9 1240 mb->append("\"", 1);
d860a1aa 1241}
fc68f6b1 1242
1243void
1244keepCapabilities(void)
1245{
329ce686 1246#if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && HAVE_SYS_CAPABILITY_H
1247
1248 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
788625af 1249 IPInterceptor.StopTransparency("capability setting has failed.");
fc68f6b1 1250 }
fc68f6b1 1251#endif
1252}
329ce686 1253
1254static void
1255restoreCapabilities(int keep)
1256{
1257#if defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H
b5f9c580
HN
1258#ifndef _LINUX_CAPABILITY_VERSION_1
1259#define _LINUX_CAPABILITY_VERSION_1 _LINUX_CAPABILITY_VERSION
1260#endif
fd3cc4b6
HN
1261 cap_user_header_t head = (cap_user_header_t) xcalloc(1, sizeof(*head));
1262 cap_user_data_t cap = (cap_user_data_t) xcalloc(1, sizeof(*cap));
329ce686 1263
92a9a48d 1264 head->version = _LINUX_CAPABILITY_VERSION_1;
329ce686 1265
1266 if (capget(head, cap) != 0) {
1267 debugs(50, 1, "Can't get current capabilities");
1268 goto nocap;
1269 }
1270
92a9a48d 1271 if (head->version != _LINUX_CAPABILITY_VERSION_1) {
6fdd856d 1272 debugs(50, 1, "Invalid capability version " << head->version << " (expected " << _LINUX_CAPABILITY_VERSION_1 << ")");
329ce686 1273 goto nocap;
1274 }
1275
1276 head->pid = 0;
1277
1278 cap->inheritable = 0;
1279 cap->effective = (1 << CAP_NET_BIND_SERVICE);
329ce686 1280
26ac0430 1281 if (IPInterceptor.TransparentActive()) {
f1e0717c 1282 cap->effective |= (1 << CAP_NET_ADMIN);
04f87469
AJ
1283#if LINUX_TPROXY2
1284 cap->effective |= (1 << CAP_NET_BROADCAST);
329ce686 1285#endif
04f87469 1286 }
329ce686 1287
1288 if (!keep)
1289 cap->permitted &= cap->effective;
1290
1291 if (capset(head, cap) != 0) {
788625af 1292 IPInterceptor.StopTransparency("Error enabling needed capabilities.");
329ce686 1293 }
1294
1295nocap:
1296 xfree(head);
1297 xfree(cap);
329ce686 1298
788625af
AJ
1299#else /* not defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H */
1300 IPInterceptor.StopTransparency("Missing needed capability support.");
329ce686 1301#endif
1302}
cc192b50 1303
1304void *
1305xmemset(void *dst, int val, size_t sz)
1306{
1307 // do debugs output
1308 debugs(63, 9, "memset: dst=" << dst << ", val=" << val << ", bytes=" << sz);
1309
1310 // call the system one to do the actual work ~safely.
1311 return memset(dst, val, sz);
1312}