]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
SourceFormat Enforcement
[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"
27bc2077
AJ
36#include "compat/initgroups.h"
37#include "compat/getaddrinfo.h"
38#include "compat/getnameinfo.h"
39#include "compat/tempnam.h"
528b2c61 40#include "fde.h"
27bc2077 41#include "ip/IpIntercept.h"
0eb49b6d 42#include "MemBuf.h"
27bc2077 43#include "ProtoPort.h"
a98bcbee 44#include "SquidMath.h"
985c86bc 45#include "SquidTime.h"
27bc2077
AJ
46#include "SwapDir.h"
47#include "wordlist.h"
44a47c6e 48
62ae0622 49#if HAVE_SYS_PRCTL_H
50#include <sys/prctl.h>
51#endif
52
090089c4 53#define DEAD_MSG "\
c5c666ab 54The Squid Cache (version %s) died.\n\
090089c4 55\n\
c5c666ab 56You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 57If a core file was created (possibly in the swap directory),\n\
b8de7ebe 58please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
784219b8 59and report the trace back to squid-bugs@squid-cache.org.\n\
090089c4 60\n\
61Thanks!\n"
62
f5b8bbc4 63static void fatal_common(const char *);
137ee196 64static void fatalvf(const char *fmt, va_list args);
f5b8bbc4 65static void mail_warranty(void);
63986a85 66#if MEM_GEN_TRACE
399e85ea 67extern void log_trace_done();
63986a85 68extern void log_trace_init(char *);
399e85ea 69#endif
329ce686 70static void restoreCapabilities(int keep);
24382924 71
941a3077 72#ifdef _SQUID_LINUX_
73/* Workaround for crappy glic header files */
e6ccf245 74SQUIDCEXTERN int backtrace(void *, int);
75SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
76SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
10da753f
FC
77#else /* _SQUID_LINUX_ */
78/* needed on Opensolaris for backtrace_symbols_fd */
79#if HAVE_EXECINFO_H
80#include <execinfo.h>
81#endif /* HAVE_EXECINFO_H */
82
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),
a98bcbee 169 Math::intPercent(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",
a98bcbee 203 t >> 10, Math::intPercent(t, mp.arena));
62e76326 204
30a4f2a8 205 t = mp.fsmblks + mp.fordblks;
62e76326 206
9e4ad609 207 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
a98bcbee 208 t >> 10, Math::intPercent(t, mp.arena));
62e76326 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
0a081cb0 339#if PRINT_STACK_TRACE
0b4639af 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_ */
10da753f 349#if defined(_SQUID_SOLARIS_) && HAVE_LIBOPCOM_STACK
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
10da753f 358#endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
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;
96e03dd8 409 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
62e76326 410
30a4f2a8 411 if (state == 0) {
32d002cb 412#if !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 {
32d002cb 421#if !MEM_GEN_TRACE
62493678 422 Debug::parseOptions(Debug::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
62493678 447 if (Debug::log_stderr > 0 && debug_log != stderr)
62e76326 448 fprintf(stderr, "FATAL: %s\n", message);
449
c5c666ab 450 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
62e76326 451 version_string);
452
2c47cf74 453 fflush(debug_log);
62e76326 454
9e4ad609 455 PrintRusage();
62e76326 456
9e4ad609 457 dumpMallocStats();
090089c4 458}
459
460/* fatal */
b8d8561b 461void
0ee4272b 462fatal(const char *message)
090089c4 463{
634243ef
AJ
464 /* suppress secondary errors from the dying */
465 shutting_down = 1;
466
429fdbec 467 releaseServerSockets();
b2c141d4 468 /* check for store_dirs_rebuilding because fatal() is often
d399be0e 469 * used in early initialization phases, long before we ever
470 * get to the store log. */
62e76326 471
bef81ea5 472 /* XXX: this should be turned into a callback-on-fatal, or
473 * a mandatory-shutdown-event or something like that.
474 * - RBC 20060819
475 */
476
975b5060 477 /*
478 * DPW 2007-07-06
479 * Call leave_suid() here to make sure that swap.state files
480 * are written as the effective user, rather than root. Squid
481 * may take on root privs during reconfigure. If squid.conf
482 * contains a "Bungled" line, fatal() will be called when the
483 * process still has root privs.
484 */
7e0f82f2 485 leave_suid();
975b5060 486
bef81ea5 487 if (0 == StoreController::store_dirs_rebuilding)
62e76326 488 storeDirWriteCleanLogs(0);
489
090089c4 490 fatal_common(message);
62e76326 491
776ff02c 492 exit(1);
090089c4 493}
494
137ee196 495/* printf-style interface for fatal */
137ee196 496void
497fatalf(const char *fmt,...)
498{
499 va_list args;
500 va_start(args, fmt);
137ee196 501 fatalvf(fmt, args);
502 va_end(args);
503}
504
505
506/* used by fatalf */
507static void
af6a12ee
AJ
508fatalvf(const char *fmt, va_list args)
509{
137ee196 510 static char fatal_str[BUFSIZ];
511 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
512 fatal(fatal_str);
513}
514
090089c4 515/* fatal with dumping core */
b8d8561b 516void
af6a12ee
AJ
517fatal_dump(const char *message)
518{
7e3ce7b9 519 failure_notify = NULL;
429fdbec 520 releaseServerSockets();
62e76326 521
090089c4 522 if (message)
62e76326 523 fatal_common(message);
524
776ff02c 525 /*
526 * Call leave_suid() here to make sure that swap.state files
527 * are written as the effective user, rather than root. Squid
528 * may take on root privs during reconfigure. If squid.conf
529 * contains a "Bungled" line, fatal() will be called when the
530 * process still has root privs.
531 */
532 leave_suid();
533
4a69c163 534 if (opt_catch_signals)
62e76326 535 storeDirWriteCleanLogs(0);
536
090089c4 537 abort();
538}
539
b8d8561b 540void
af6a12ee
AJ
541debug_trap(const char *message)
542{
4a69c163 543 if (!opt_catch_signals)
62e76326 544 fatal_dump(message);
545
a3d5953d 546 _db_print("WARNING: %s\n", message);
85b701ed 547}
548
b8d8561b 549void
af6a12ee
AJ
550sig_child(int sig)
551{
a50bfe93 552#ifndef _SQUID_MSWIN_
30a4f2a8 553#ifdef _SQUID_NEXT_
554 union wait status;
555#else
62e76326 556
090089c4 557 int status;
090089c4 558#endif
62e76326 559
ff8d0ea6 560 pid_t pid;
090089c4 561
30a4f2a8 562 do {
563#ifdef _SQUID_NEXT_
62e76326 564 pid = wait3(&status, WNOHANG, NULL);
090089c4 565#else
62e76326 566
567 pid = waitpid(-1, &status, WNOHANG);
090089c4 568#endif
96e03dd8 569 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 570#if HAVE_SIGACTION
62e76326 571
30a4f2a8 572 } while (pid > 0);
62e76326 573
234967c9 574#else
62e76326 575
576 }
577
3d0ac046 578 while (pid > 0 || (pid < 0 && errno == EINTR));
30a4f2a8 579 signal(sig, sig_child);
62e76326 580
a50bfe93 581#endif
234967c9 582#endif
30a4f2a8 583}
44a47c6e 584
0ee4272b 585const char *
0673c0ba 586getMyHostname(void)
44a47c6e 587{
95d659f0 588 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 589 static int present = 0;
cc192b50 590 struct addrinfo *AI = NULL;
ad61a2b4 591 IpAddress sa;
62e76326 592
af85f811 593 if (Config.visibleHostname != NULL)
62e76326 594 return Config.visibleHostname;
595
d20b1cd0 596 if (present)
62e76326 597 return host;
598
d20b1cd0 599 host[0] = '\0';
62e76326 600
cc192b50 601 if (Config.Sockaddr.http && sa.IsAnyAddr())
602 sa = Config.Sockaddr.http->s;
62e76326 603
aa2b5399 604#if USE_SSL
62e76326 605
cc192b50 606 if (Config.Sockaddr.https && sa.IsAnyAddr())
607 sa = Config.Sockaddr.https->http.s;
62e76326 608
aa2b5399 609#endif
cc192b50 610
aa2b5399 611 /*
612 * If the first http_port address has a specific address, try a
613 * reverse DNS lookup on it.
614 */
26ac0430 615 if ( !sa.IsAnyAddr() ) {
62e76326 616
cc192b50 617 sa.GetAddrInfo(AI);
618 /* we are looking for a name. */
27bc2077 619 if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, NULL, 0, NI_NAMEREQD ) == 0) {
62e76326 620 /* DNS lookup successful */
621 /* use the official name from DNS lookup */
cc192b50 622 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
bf8fe701 623
62e76326 624 present = 1;
625
cc192b50 626 sa.FreeAddrInfo(AI);
627
62e76326 628 if (strchr(host, '.'))
629 return host;
62e76326 630 }
631
cc192b50 632 sa.FreeAddrInfo(AI);
633 debugs(50, 1, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
26ac0430 634 } else {
cc192b50 635 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
636 debugs(50, 1, "WARNING: gethostname failed: " << xstrerror());
26ac0430 637 } else {
cc192b50 638 /* Verify that the hostname given resolves properly */
639 struct addrinfo hints;
640 memset(&hints, 0, sizeof(addrinfo));
641 hints.ai_flags = AI_CANONNAME;
642
27bc2077 643 if (getaddrinfo(host, NULL, NULL, &AI) == 0) {
cc192b50 644 /* DNS lookup successful */
645 /* use the official name from DNS lookup */
626a9889 646 debugs(50, 6, "getMyHostname: '" << host << "' has rDNS.");
cc192b50 647 present = 1;
648
649 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
26ac0430 650 if (AI) {
27bc2077 651 freeaddrinfo(AI);
cc192b50 652 AI = NULL;
653 }
62e76326 654
cc192b50 655 return host;
656 }
657
27bc2077 658 if (AI) freeaddrinfo(AI);
626a9889 659 debugs(50, 1, "WARNING: '" << host << "' rDNS test failed: " << xstrerror());
cc192b50 660 }
44a47c6e 661 }
62e76326 662
cc192b50 663 /* throw a fatal configuration error when the Host/IP given has bad DNS/rDNS. */
a572d8be 664 if (opt_send_signal == -1)
665 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
666 else
667 return ("localhost");
668
d20b1cd0 669 return NULL; /* keep compiler happy */
44a47c6e 670}
671
98829f69 672const char *
673uniqueHostname(void)
674{
23c6ebc4 675 debugs(21, 3, HERE << " Config: '" << Config.uniqueHostname << "'");
98829f69 676 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
677}
678
23c6ebc4 679/** leave a priviliged section. (Give up any privilegies)
30a4f2a8 680 * Routines that need privilegies can rap themselves in enter_suid()
681 * and leave_suid()
682 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 683 */
b8d8561b 684void
0673c0ba 685leave_suid(void)
12b9e9b1 686{
36584579 687 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
62e76326 688
e3d74828 689 if (Config.effectiveGroup) {
690
691#if HAVE_SETGROUPS
692
693 setgroups(1, &Config2.effectiveGroupID);
694
695#endif
696
697 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 698 debugs(50, 0, "ALERT: setgid: " << xstrerror());
e3d74828 699
700 }
701
12b9e9b1 702 if (geteuid() != 0)
62e76326 703 return;
704
12b9e9b1 705 /* Started as a root, check suid option */
b6f794d6 706 if (Config.effectiveUser == NULL)
62e76326 707 return;
708
36584579 709 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
62e76326 710
e3d74828 711 if (!Config.effectiveGroup) {
62e76326 712
e3d74828 713 if (setgid(Config2.effectiveGroupID) < 0)
bf8fe701 714 debugs(50, 0, "ALERT: setgid: " << xstrerror());
62e76326 715
e3d74828 716 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
bf8fe701 717 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
718 Config.effectiveUser << " and Group " <<
719 (unsigned) Config2.effectiveGroupID << "");
e3d74828 720 }
721 }
62e76326 722
234967c9 723#if HAVE_SETRESUID
62e76326 724
d20b1cd0 725 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
bf8fe701 726 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
62e76326 727
234967c9 728#elif HAVE_SETEUID
62e76326 729
d20b1cd0 730 if (seteuid(Config2.effectiveUserID) < 0)
bf8fe701 731 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
62e76326 732
234967c9 733#else
62e76326 734
d20b1cd0 735 if (setuid(Config2.effectiveUserID) < 0)
bf8fe701 736 debugs(50, 0, "ALERT: setuid: " << xstrerror());
62e76326 737
fc68f6b1 738#endif
fc68f6b1 739
329ce686 740 restoreCapabilities(1);
fc68f6b1 741
62ae0622 742#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
743 /* Set Linux DUMPABLE flag */
744 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 745 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 746
234967c9 747#endif
748}
749
30a4f2a8 750/* Enter a privilegied section */
b8d8561b 751void
0673c0ba 752enter_suid(void)
234967c9 753{
36584579 754 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
234967c9 755#if HAVE_SETRESUID
62e76326 756
e6ccf245 757 setresuid((uid_t)-1, 0, (uid_t)-1);
234967c9 758#else
62e76326 759
234967c9 760 setuid(0);
761#endif
62ae0622 762#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
763 /* Set Linux DUMPABLE flag */
764
765 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 766 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 767
768#endif
234967c9 769}
770
30a4f2a8 771/* Give up the posibility to gain privilegies.
772 * this should be used before starting a sub process
773 */
b8d8561b 774void
0673c0ba 775no_suid(void)
234967c9 776{
777 uid_t uid;
30a4f2a8 778 leave_suid();
234967c9 779 uid = geteuid();
329ce686 780 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
62e76326 781
234967c9 782 setuid(0);
62e76326 783
429fdbec 784 if (setuid(uid) < 0)
bf8fe701 785 debugs(50, 1, "no_suid: setuid: " << xstrerror());
62e76326 786
329ce686 787 restoreCapabilities(0);
788
62ae0622 789#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
790 /* Set Linux DUMPABLE flag */
791 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 792 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 793
234967c9 794#endif
12b9e9b1 795}
ccff9601 796
b8d8561b 797void
0673c0ba 798writePidFile(void)
ccff9601 799{
9e4ad609 800 int fd;
0b4639af 801 const char *f = NULL;
973e9fe1 802 mode_t old_umask;
9e4ad609 803 char buf[32];
62e76326 804
9e4ad609 805 if ((f = Config.pidFilename) == NULL)
62e76326 806 return;
807
9e4ad609 808 if (!strcmp(Config.pidFilename, "none"))
62e76326 809 return;
810
30a4f2a8 811 enter_suid();
62e76326 812
973e9fe1 813 old_umask = umask(022);
62e76326 814
c4aefe96 815 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT);
62e76326 816
973e9fe1 817 umask(old_umask);
62e76326 818
30a4f2a8 819 leave_suid();
62e76326 820
9e4ad609 821 if (fd < 0) {
bf8fe701 822 debugs(50, 0, "" << f << ": " << xstrerror());
62e76326 823 debug_trap("Could not write pid file");
824 return;
ccff9601 825 }
62e76326 826
56878878 827 snprintf(buf, 32, "%d\n", (int) getpid());
1f7c9178 828 FD_WRITE_METHOD(fd, buf, strlen(buf));
9e4ad609 829 file_close(fd);
ccff9601 830}
c4fb974e 831
832
ff8d0ea6 833pid_t
0673c0ba 834readPidFile(void)
7690e8eb 835{
836 FILE *pid_fp = NULL;
9e4ad609 837 const char *f = Config.pidFilename;
1ee742a2 838 char *chroot_f = NULL;
ff8d0ea6 839 pid_t pid = -1;
840 int i;
7690e8eb 841
9e4ad609 842 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7dbca7a4 843 fprintf(stderr, APP_SHORTNAME ": ERROR: No pid file name defined\n");
62e76326 844 exit(1);
7690e8eb 845 }
62e76326 846
1ee742a2 847 if (Config.chroot_dir && geteuid() == 0) {
848 int len = strlen(Config.chroot_dir) + 1 + strlen(f) + 1;
849 chroot_f = (char *)xmalloc(strlen(Config.chroot_dir) + 1 + strlen(f) + 1);
850 snprintf(chroot_f, len, "%s/%s", Config.chroot_dir, f);
851 f = chroot_f;
852 }
853
7690e8eb 854 pid_fp = fopen(f, "r");
62e76326 855
7690e8eb 856 if (pid_fp != NULL) {
62e76326 857 pid = 0;
858
859 if (fscanf(pid_fp, "%d", &i) == 1)
860 pid = (pid_t) i;
861
862 fclose(pid_fp);
7690e8eb 863 } else {
62e76326 864 if (errno != ENOENT) {
7dbca7a4 865 fprintf(stderr, APP_SHORTNAME ": ERROR: Could not read pid file\n");
62e76326 866 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
867 exit(1);
868 }
7690e8eb 869 }
62e76326 870
1ee742a2 871 safe_free(chroot_f);
7690e8eb 872 return pid;
873}
874
875
b8d8561b 876void
0673c0ba 877setMaxFD(void)
c4fb974e 878{
234967c9 879#if HAVE_SETRLIMIT
c4fb974e 880 /* try to use as many file descriptors as possible */
881 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
62e76326 882
c4fb974e 883 struct rlimit rl;
884#if defined(RLIMIT_NOFILE)
62e76326 885
c4fb974e 886 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
bf8fe701 887 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 888 } else {
62e76326 889 rl.rlim_cur = Squid_MaxFD;
890
891 if (rl.rlim_cur > rl.rlim_max)
892 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
893
894 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
895 snprintf(tmp_error_buf, ERROR_BUF_SZ,
896 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
897 fatal_dump(tmp_error_buf);
898 }
c4fb974e 899 }
62e76326 900
c4fb974e 901#elif defined(RLIMIT_OFILE)
902 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
bf8fe701 903 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 904 } else {
62e76326 905 rl.rlim_cur = Squid_MaxFD;
906
907 if (rl.rlim_cur > rl.rlim_max)
908 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
909
910 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
911 snprintf(tmp_error_buf, ERROR_BUF_SZ,
912 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
913 fatal_dump(tmp_error_buf);
914 }
c4fb974e 915 }
62e76326 916
c4fb974e 917#endif
c4fb974e 918#else /* HAVE_SETRLIMIT */
bf8fe701 919 debugs(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
62e76326 920
30a4f2a8 921#endif /* HAVE_SETRLIMIT */
922
923#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
62e76326 924
30a4f2a8 925 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
bf8fe701 926 debugs(50, 0, "getrlimit: RLIMIT_DATA: " << xstrerror());
88738790 927 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 928 rl.rlim_cur = rl.rlim_max; /* set it to the max */
929
930 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
931 snprintf(tmp_error_buf, ERROR_BUF_SZ,
932 "setrlimit: RLIMIT_DATA: %s", xstrerror());
933 fatal_dump(tmp_error_buf);
934 }
30a4f2a8 935 }
62e76326 936
30a4f2a8 937#endif /* RLIMIT_DATA */
ad7ef91a 938#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
939 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
bf8fe701 940 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
88738790 941 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 942 rl.rlim_cur = rl.rlim_max; /* set it to the max */
943
944 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
945 snprintf(tmp_error_buf, ERROR_BUF_SZ,
946 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
947 fatal_dump(tmp_error_buf);
948 }
ad7ef91a 949 }
62e76326 950
ad7ef91a 951#endif /* RLIMIT_VMEM */
c4fb974e 952}
3a57089e 953
b8d8561b 954void
ea3a2a69 955squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 956{
957#if HAVE_SIGACTION
62e76326 958
30a4f2a8 959 struct sigaction sa;
960 sa.sa_handler = func;
961 sa.sa_flags = flags;
962 sigemptyset(&sa.sa_mask);
62e76326 963
30a4f2a8 964 if (sigaction(sig, &sa, NULL) < 0)
bf8fe701 965 debugs(50, 0, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerror());
62e76326 966
30a4f2a8 967#else
06648839 968#ifdef _SQUID_MSWIN_
969 /*
970 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
971 are supported, so we must care of don't call signal() for other value.
972 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
973 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
974 */
975 switch (sig) {
976
977 case SIGINT:
978
979 case SIGILL:
980
981 case SIGFPE:
982
983 case SIGTERM:
984
985 case SIGBREAK:
986
987 case SIGABRT:
988 break;
989
990 case SIGSEGV:
991 WIN32_ExceptionHandlerInit();
992 break;
993
994 case SIGBUS:
995 WIN32_ExceptionHandlerInit();
996 return;
997 break; /* Nor reached */
998
999 default:
1000 return;
1001 break; /* Nor reached */
1002 }
1003
1004#endif
62e76326 1005
06648839 1006 signal(sig, func);
62e76326 1007
30a4f2a8 1008#endif
1009}
396c5745 1010
70364f29 1011void
1012logsFlush(void)
1013{
1014 if (debug_log)
62e76326 1015 fflush(debug_log);
70364f29 1016}
88738790 1017
16300b58 1018void
0e473d70 1019kb_incr(kb_t * k, size_t v)
a7c05555 1020{
0e473d70 1021 k->bytes += v;
1022 k->kb += (k->bytes >> 10);
1023 k->bytes &= 0x3FF;
a7c05555 1024}
c1dabf04 1025
a00a7c85 1026void
6bbf9cc4 1027debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 1028{
1029 MemBuf mb;
1030 Packer p;
6bbf9cc4 1031 assert(label && obj && pm);
2fe7eff9 1032 mb.init();
a00a7c85 1033 packerToMemInit(&p, &mb);
0cdcddb9 1034 (*pm) (obj, &p);
bf8fe701 1035 debugs(section, level, "" << label << "" << mb.buf << "");
a00a7c85 1036 packerClean(&p);
2fe7eff9 1037 mb.clean();
a00a7c85 1038}
d548ee64 1039
0e70aa1e 1040void
1041parseEtcHosts(void)
1042{
1043 FILE *fp;
1044 char buf[1024];
1045 char buf2[512];
1046 char *nt = buf;
1047 char *lt = buf;
fa2bfbab 1048
0e70aa1e 1049 if (NULL == Config.etcHostsPath)
62e76326 1050 return;
1051
0e70aa1e 1052 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 1053 return;
1054
0e70aa1e 1055 fp = fopen(Config.etcHostsPath, "r");
62e76326 1056
0e70aa1e 1057 if (fp == NULL) {
bf8fe701 1058 debugs(1, 1, "parseEtcHosts: " << Config.etcHostsPath << ": " << xstrerror());
62e76326 1059 return;
0e70aa1e 1060 }
62e76326 1061
ec4daaa5 1062#ifdef _SQUID_WIN32_
c4aefe96 1063 setmode(fileno(fp), O_TEXT);
62e76326 1064
c4aefe96 1065#endif
62e76326 1066
0e70aa1e 1067 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1068 wordlist *hosts = NULL;
1069 char *addr;
1070
c31616ae 1071 if (buf[0] == '#') /* MS-windows likes to add comments */
1072 continue;
1073
7a10c315 1074 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1075
1076 lt = buf;
1077
1078 addr = buf;
1079
bf8fe701 1080 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
62e76326 1081
1082 nt = strpbrk(lt, w_space);
1083
1084 if (nt == NULL) /* empty line */
1085 continue;
1086
1087 *nt = '\0'; /* null-terminate the address */
1088
bf8fe701 1089 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
62e76326 1090
1091 lt = nt + 1;
1092
1093 while ((nt = strpbrk(lt, w_space))) {
1094 char *host = NULL;
1095
1096 if (nt == lt) { /* multiple spaces */
bf8fe701 1097 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
62e76326 1098 lt = nt + 1;
1099 continue;
1100 }
1101
1102 *nt = '\0';
bf8fe701 1103 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
62e76326 1104
1105 if (Config.appendDomain && !strchr(lt, '.')) {
1106 /* I know it's ugly, but it's only at reconfig */
1107 strncpy(buf2, lt, 512);
3fbd26b5 1108 strncat(buf2, Config.appendDomain, 512 - strlen(lt) - 1);
62e76326 1109 host = buf2;
1110 } else {
1111 host = lt;
1112 }
1113
f6a72b33
AJ
1114 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1115 /* invalid address, continuing is useless */
1116 wordlistDestroy(&hosts);
1117 hosts = NULL;
1118 break;
1119 }
62e76326 1120 wordlistAdd(&hosts, host);
1121
1122 lt = nt + 1;
1123 }
1124
9e008dda 1125 if (hosts) {
f6a72b33
AJ
1126 fqdncacheAddEntryFromHosts(addr, hosts);
1127 wordlistDestroy(&hosts);
1128 }
0e70aa1e 1129 }
62e76326 1130
1f3c7397 1131 fclose (fp);
0e70aa1e 1132}
52f772de 1133
1134int
1135getMyPort(void)
1136{
52f772de 1137 if (Config.Sockaddr.http)
cc192b50 1138 return Config.Sockaddr.http->s.GetPort();
62e76326 1139
a2727cdb 1140#if USE_SSL
62e76326 1141
a2727cdb 1142 if (Config.Sockaddr.https)
cc192b50 1143 return Config.Sockaddr.https->http.s.GetPort();
62e76326 1144
52f772de 1145#endif
62e76326 1146
a2727cdb 1147 fatal("No port defined");
62e76326 1148
bac6d4bd 1149 return 0; /* NOT REACHED */
52f772de 1150}
d860a1aa 1151
c642c141
AJ
1152/*
1153 * Set the umask to at least the given mask. This is in addition
1154 * to the umask set at startup
1155 */
1156void
1157setUmask(mode_t mask)
1158{
1159 // No way to get the current umask value without setting it.
1160 static const mode_t orig_umask = umask(mask); // once, to get
1161 umask(mask | orig_umask); // always, to set
1162}
d860a1aa 1163
1164/*
1165 * Inverse of strwordtok. Quotes a word if needed
1166 */
42419a95 1167void
d860a1aa 1168strwordquote(MemBuf * mb, const char *str)
1169{
1170 int quoted = 0;
62e76326 1171
d860a1aa 1172 if (strchr(str, ' ')) {
62e76326 1173 quoted = 1;
2fe7eff9 1174 mb->append("\"", 1);
d860a1aa 1175 }
62e76326 1176
d860a1aa 1177 while (*str) {
dc1af3cf 1178 int l = strcspn(str, "\"\\\n\r");
2fe7eff9 1179 mb->append(str, l);
62e76326 1180 str += l;
1181
26ac0430 1182 switch (*str) {
dc1af3cf 1183
1184 case '\n':
2fe7eff9 1185 mb->append("\\n", 2);
dc1af3cf 1186 str++;
1187 break;
1188
1189 case '\r':
2fe7eff9 1190 mb->append("\\r", 2);
dc1af3cf 1191 str++;
1192 break;
1193
1194 case '\0':
1195 break;
1196
1197 default:
2fe7eff9 1198 mb->append("\\", 1);
1199 mb->append(str, 1);
62e76326 1200 str++;
dc1af3cf 1201 break;
62e76326 1202 }
d860a1aa 1203 }
62e76326 1204
d860a1aa 1205 if (quoted)
2fe7eff9 1206 mb->append("\"", 1);
d860a1aa 1207}
fc68f6b1 1208
1209void
1210keepCapabilities(void)
1211{
b64b6030 1212#if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && USE_LIBCAP
329ce686 1213
1214 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
85944c1c 1215 IpInterceptor.StopTransparency("capability setting has failed.");
fc68f6b1 1216 }
fc68f6b1 1217#endif
1218}
329ce686 1219
1220static void
1221restoreCapabilities(int keep)
1222{
9e008dda 1223 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
b64b6030 1224#if USE_LIBCAP
c3487a77
HN
1225 cap_t caps;
1226 if (keep)
1227 caps = cap_get_proc();
1228 else
1229 caps = cap_init();
1230 if (!caps) {
1231 IpInterceptor.StopTransparency("Can't get current capabilities");
9e008dda 1232 } else {
c3487a77
HN
1233 int ncaps = 0;
1234 int rc = 0;
1235 cap_value_t cap_list[10];
1236 cap_list[ncaps++] = CAP_NET_BIND_SERVICE;
87632631 1237
fc32ce2e 1238 if (IpInterceptor.TransparentActive()) {
c3487a77 1239 cap_list[ncaps++] = CAP_NET_ADMIN;
04f87469 1240#if LINUX_TPROXY2
c3487a77 1241 cap_list[ncaps++] = CAP_NET_BROADCAST;
329ce686 1242#endif
fc32ce2e 1243 }
329ce686 1244
c3487a77
HN
1245 cap_clear_flag(caps, CAP_EFFECTIVE);
1246 rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1247 rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
329ce686 1248
c3487a77 1249 if (rc || cap_set_proc(caps) != 0) {
85944c1c 1250 IpInterceptor.StopTransparency("Error enabling needed capabilities.");
b5bd96ce 1251 }
c3487a77 1252 cap_free(caps);
329ce686 1253 }
b64b6030 1254#elif defined(_SQUID_LINUX_)
85944c1c 1255 IpInterceptor.StopTransparency("Missing needed capability support.");
b5bd96ce 1256#endif /* HAVE_SYS_CAPABILITY_H */
329ce686 1257}
cc192b50 1258
1259void *
1260xmemset(void *dst, int val, size_t sz)
1261{
1262 // do debugs output
1263 debugs(63, 9, "memset: dst=" << dst << ", val=" << val << ", bytes=" << sz);
1264
1265 // call the system one to do the actual work ~safely.
1266 return memset(dst, val, sz);
1267}