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