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