os.c revision 193149
1/* 2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: os.c,v 1.89.12.5 2009/03/02 03:03:54 marka Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23#include <stdarg.h> 24 25#include <sys/types.h> /* dev_t FreeBSD 2.1 */ 26#include <sys/stat.h> 27 28#include <ctype.h> 29#include <errno.h> 30#include <fcntl.h> 31#include <grp.h> /* Required for initgroups() on IRIX. */ 32#include <pwd.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <signal.h> 36#include <syslog.h> 37#ifdef HAVE_TZSET 38#include <time.h> 39#endif 40#include <unistd.h> 41 42#include <isc/buffer.h> 43#include <isc/file.h> 44#include <isc/print.h> 45#include <isc/resource.h> 46#include <isc/result.h> 47#include <isc/strerror.h> 48#include <isc/string.h> 49 50#include <named/main.h> 51#include <named/os.h> 52#ifdef HAVE_LIBSCF 53#include <named/ns_smf_globals.h> 54#endif 55 56static char *pidfile = NULL; 57static int devnullfd = -1; 58 59#ifndef ISC_FACILITY 60#define ISC_FACILITY LOG_DAEMON 61#endif 62 63/* 64 * If there's no <linux/capability.h>, we don't care about <sys/prctl.h> 65 */ 66#ifndef HAVE_LINUX_CAPABILITY_H 67#undef HAVE_SYS_PRCTL_H 68#endif 69 70/* 71 * Linux defines: 72 * (T) HAVE_LINUXTHREADS 73 * (C) HAVE_SYS_CAPABILITY_H (or HAVE_LINUX_CAPABILITY_H) 74 * (P) HAVE_SYS_PRCTL_H 75 * The possible cases are: 76 * none: setuid() normally 77 * T: no setuid() 78 * C: setuid() normally, drop caps (keep CAP_SETUID) 79 * T+C: no setuid(), drop caps (don't keep CAP_SETUID) 80 * T+C+P: setuid() early, drop caps (keep CAP_SETUID) 81 * C+P: setuid() normally, drop caps (keep CAP_SETUID) 82 * P: not possible 83 * T+P: not possible 84 * 85 * if (C) 86 * caps = BIND_SERVICE + CHROOT + SETGID 87 * if ((T && C && P) || !T) 88 * caps += SETUID 89 * endif 90 * capset(caps) 91 * endif 92 * if (T && C && P && -u) 93 * setuid() 94 * else if (T && -u) 95 * fail 96 * --> start threads 97 * if (!T && -u) 98 * setuid() 99 * if (C && (P || !-u)) 100 * caps = BIND_SERVICE 101 * capset(caps) 102 * endif 103 * 104 * It will be nice when Linux threads work properly with setuid(). 105 */ 106 107#ifdef HAVE_LINUXTHREADS 108static pid_t mainpid = 0; 109#endif 110 111static struct passwd *runas_pw = NULL; 112static isc_boolean_t done_setuid = ISC_FALSE; 113static int dfd[2] = { -1, -1 }; 114 115#ifdef HAVE_LINUX_CAPABILITY_H 116 117static isc_boolean_t non_root = ISC_FALSE; 118static isc_boolean_t non_root_caps = ISC_FALSE; 119 120#ifdef HAVE_SYS_CAPABILITY_H 121#include <sys/capability.h> 122#else 123/*% 124 * We define _LINUX_FS_H to prevent it from being included. We don't need 125 * anything from it, and the files it includes cause warnings with 2.2 126 * kernels, and compilation failures (due to conflicts between <linux/string.h> 127 * and <string.h>) on 2.3 kernels. 128 */ 129#define _LINUX_FS_H 130#include <linux/capability.h> 131#include <syscall.h> 132#ifndef SYS_capset 133#ifndef __NR_capset 134#include <asm/unistd.h> /* Slackware 4.0 needs this. */ 135#endif /* __NR_capset */ 136#define SYS_capset __NR_capset 137#endif /* SYS_capset */ 138#endif /* HAVE_SYS_CAPABILITY_H */ 139 140#ifdef HAVE_SYS_PRCTL_H 141#include <sys/prctl.h> /* Required for prctl(). */ 142 143/* 144 * If the value of PR_SET_KEEPCAPS is not in <sys/prctl.h>, define it 145 * here. This allows setuid() to work on systems running a new enough 146 * kernel but with /usr/include/linux pointing to "standard" kernel 147 * headers. 148 */ 149#ifndef PR_SET_KEEPCAPS 150#define PR_SET_KEEPCAPS 8 151#endif 152 153#endif /* HAVE_SYS_PRCTL_H */ 154 155#ifdef HAVE_LIBCAP 156#define SETCAPS_FUNC "cap_set_proc " 157#else 158typedef unsigned int cap_t; 159#define SETCAPS_FUNC "syscall(capset) " 160#endif /* HAVE_LIBCAP */ 161 162static void 163linux_setcaps(cap_t caps) { 164#ifndef HAVE_LIBCAP 165 struct __user_cap_header_struct caphead; 166 struct __user_cap_data_struct cap; 167#endif 168 char strbuf[ISC_STRERRORSIZE]; 169 170 if ((getuid() != 0 && !non_root_caps) || non_root) 171 return; 172#ifndef HAVE_LIBCAP 173 memset(&caphead, 0, sizeof(caphead)); 174 caphead.version = _LINUX_CAPABILITY_VERSION; 175 caphead.pid = 0; 176 memset(&cap, 0, sizeof(cap)); 177 cap.effective = caps; 178 cap.permitted = caps; 179 cap.inheritable = 0; 180#endif 181#ifdef HAVE_LIBCAP 182 if (cap_set_proc(caps) < 0) { 183#else 184 if (syscall(SYS_capset, &caphead, &cap) < 0) { 185#endif 186 isc__strerror(errno, strbuf, sizeof(strbuf)); 187 ns_main_earlyfatal(SETCAPS_FUNC "failed: %s:" 188 " please ensure that the capset kernel" 189 " module is loaded. see insmod(8)", 190 strbuf); 191 } 192} 193 194#ifdef HAVE_LIBCAP 195#define SET_CAP(flag) \ 196 do { \ 197 capval = (flag); \ 198 cap_flag_value_t curval; \ 199 err = cap_get_flag(curcaps, capval, CAP_PERMITTED, &curval); \ 200 if (err != -1 && curval) { \ 201 err = cap_set_flag(caps, CAP_EFFECTIVE, 1, &capval, CAP_SET); \ 202 if (err == -1) { \ 203 isc__strerror(errno, strbuf, sizeof(strbuf)); \ 204 ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \ 205 } \ 206 \ 207 err = cap_set_flag(caps, CAP_PERMITTED, 1, &capval, CAP_SET); \ 208 if (err == -1) { \ 209 isc__strerror(errno, strbuf, sizeof(strbuf)); \ 210 ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \ 211 } \ 212 } \ 213 } while (0) 214#define INIT_CAP \ 215 do { \ 216 caps = cap_init(); \ 217 if (caps == NULL) { \ 218 isc__strerror(errno, strbuf, sizeof(strbuf)); \ 219 ns_main_earlyfatal("cap_init failed: %s", strbuf); \ 220 } \ 221 curcaps = cap_get_proc(); \ 222 if (curcaps == NULL) { \ 223 isc__strerror(errno, strbuf, sizeof(strbuf)); \ 224 ns_main_earlyfatal("cap_get_proc failed: %s", strbuf); \ 225 } \ 226 } while (0) 227#define FREE_CAP \ 228 { \ 229 cap_free(caps); \ 230 cap_free(curcaps); \ 231 } while (0) 232#else 233#define SET_CAP(flag) do { caps |= (1 << (flag)); } while (0) 234#define INIT_CAP do { caps = 0; } while (0) 235#endif /* HAVE_LIBCAP */ 236 237static void 238linux_initialprivs(void) { 239 cap_t caps; 240#ifdef HAVE_LIBCAP 241 cap_t curcaps; 242 cap_value_t capval; 243 char strbuf[ISC_STRERRORSIZE]; 244 int err; 245#endif 246 247 /*% 248 * We don't need most privileges, so we drop them right away. 249 * Later on linux_minprivs() will be called, which will drop our 250 * capabilities to the minimum needed to run the server. 251 */ 252 INIT_CAP; 253 254 /* 255 * We need to be able to bind() to privileged ports, notably port 53! 256 */ 257 SET_CAP(CAP_NET_BIND_SERVICE); 258 259 /* 260 * We need chroot() initially too. 261 */ 262 SET_CAP(CAP_SYS_CHROOT); 263 264#if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS) 265 /* 266 * We can setuid() only if either the kernel supports keeping 267 * capabilities after setuid() (which we don't know until we've 268 * tried) or we're not using threads. If either of these is 269 * true, we want the setuid capability. 270 */ 271 SET_CAP(CAP_SETUID); 272#endif 273 274 /* 275 * Since we call initgroups, we need this. 276 */ 277 SET_CAP(CAP_SETGID); 278 279 /* 280 * Without this, we run into problems reading a configuration file 281 * owned by a non-root user and non-world-readable on startup. 282 */ 283 SET_CAP(CAP_DAC_READ_SEARCH); 284 285 /* 286 * XXX We might want to add CAP_SYS_RESOURCE, though it's not 287 * clear it would work right given the way linuxthreads work. 288 * XXXDCL But since we need to be able to set the maximum number 289 * of files, the stack size, data size, and core dump size to 290 * support named.conf options, this is now being added to test. 291 */ 292 SET_CAP(CAP_SYS_RESOURCE); 293 294 linux_setcaps(caps); 295 296#ifdef HAVE_LIBCAP 297 FREE_CAP; 298#endif 299} 300 301static void 302linux_minprivs(void) { 303 cap_t caps; 304#ifdef HAVE_LIBCAP 305 cap_t curcaps; 306 cap_value_t capval; 307 char strbuf[ISC_STRERRORSIZE]; 308 int err; 309#endif 310 311 INIT_CAP; 312 /*% 313 * Drop all privileges except the ability to bind() to privileged 314 * ports. 315 * 316 * It's important that we drop CAP_SYS_CHROOT. If we didn't, it 317 * chroot() could be used to escape from the chrooted area. 318 */ 319 320 SET_CAP(CAP_NET_BIND_SERVICE); 321 322 /* 323 * XXX We might want to add CAP_SYS_RESOURCE, though it's not 324 * clear it would work right given the way linuxthreads work. 325 * XXXDCL But since we need to be able to set the maximum number 326 * of files, the stack size, data size, and core dump size to 327 * support named.conf options, this is now being added to test. 328 */ 329 SET_CAP(CAP_SYS_RESOURCE); 330 331 linux_setcaps(caps); 332 333#ifdef HAVE_LIBCAP 334 FREE_CAP; 335#endif 336} 337 338#ifdef HAVE_SYS_PRCTL_H 339static void 340linux_keepcaps(void) { 341 char strbuf[ISC_STRERRORSIZE]; 342 /*% 343 * Ask the kernel to allow us to keep our capabilities after we 344 * setuid(). 345 */ 346 347 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { 348 if (errno != EINVAL) { 349 isc__strerror(errno, strbuf, sizeof(strbuf)); 350 ns_main_earlyfatal("prctl() failed: %s", strbuf); 351 } 352 } else { 353 non_root_caps = ISC_TRUE; 354 if (getuid() != 0) 355 non_root = ISC_TRUE; 356 } 357} 358#endif 359 360#endif /* HAVE_LINUX_CAPABILITY_H */ 361 362 363static void 364setup_syslog(const char *progname) { 365 int options; 366 367 options = LOG_PID; 368#ifdef LOG_NDELAY 369 options |= LOG_NDELAY; 370#endif 371 openlog(isc_file_basename(progname), options, ISC_FACILITY); 372} 373 374void 375ns_os_init(const char *progname) { 376 setup_syslog(progname); 377#ifdef HAVE_LINUX_CAPABILITY_H 378 linux_initialprivs(); 379#endif 380#ifdef HAVE_LINUXTHREADS 381 mainpid = getpid(); 382#endif 383#ifdef SIGXFSZ 384 signal(SIGXFSZ, SIG_IGN); 385#endif 386} 387 388void 389ns_os_daemonize(void) { 390 pid_t pid; 391 char strbuf[ISC_STRERRORSIZE]; 392 393 if (pipe(dfd) == -1) { 394 isc__strerror(errno, strbuf, sizeof(strbuf)); 395 ns_main_earlyfatal("pipe(): %s", strbuf); 396 } 397 398 pid = fork(); 399 if (pid == -1) { 400 isc__strerror(errno, strbuf, sizeof(strbuf)); 401 ns_main_earlyfatal("fork(): %s", strbuf); 402 } 403 if (pid != 0) { 404 int n; 405 /* 406 * Wait for the child to finish loading for the first time. 407 * This would be so much simpler if fork() worked once we 408 * were multi-threaded. 409 */ 410 (void)close(dfd[1]); 411 do { 412 char buf; 413 n = read(dfd[0], &buf, 1); 414 if (n == 1) 415 _exit(0); 416 } while (n == -1 && errno == EINTR); 417 _exit(1); 418 } 419 (void)close(dfd[0]); 420 421 /* 422 * We're the child. 423 */ 424 425#ifdef HAVE_LINUXTHREADS 426 mainpid = getpid(); 427#endif 428 429 if (setsid() == -1) { 430 isc__strerror(errno, strbuf, sizeof(strbuf)); 431 ns_main_earlyfatal("setsid(): %s", strbuf); 432 } 433 434 /* 435 * Try to set stdin, stdout, and stderr to /dev/null, but press 436 * on even if it fails. 437 * 438 * XXXMLG The close() calls here are unneeded on all but NetBSD, but 439 * are harmless to include everywhere. dup2() is supposed to close 440 * the FD if it is in use, but unproven-pthreads-0.16 is broken 441 * and will end up closing the wrong FD. This will be fixed eventually, 442 * and these calls will be removed. 443 */ 444 if (devnullfd != -1) { 445 if (devnullfd != STDIN_FILENO) { 446 (void)close(STDIN_FILENO); 447 (void)dup2(devnullfd, STDIN_FILENO); 448 } 449 if (devnullfd != STDOUT_FILENO) { 450 (void)close(STDOUT_FILENO); 451 (void)dup2(devnullfd, STDOUT_FILENO); 452 } 453 if (devnullfd != STDERR_FILENO) { 454 (void)close(STDERR_FILENO); 455 (void)dup2(devnullfd, STDERR_FILENO); 456 } 457 } 458} 459 460void 461ns_os_started(void) { 462 char buf = 0; 463 464 /* 465 * Signal to the parent that we started successfully. 466 */ 467 if (dfd[0] != -1 && dfd[1] != -1) { 468 if (write(dfd[1], &buf, 1) != 1) 469 ns_main_earlyfatal("unable to signal parent that we " 470 "otherwise started successfully."); 471 close(dfd[1]); 472 dfd[0] = dfd[1] = -1; 473 } 474} 475 476void 477ns_os_opendevnull(void) { 478 devnullfd = open("/dev/null", O_RDWR, 0); 479} 480 481void 482ns_os_closedevnull(void) { 483 if (devnullfd != STDIN_FILENO && 484 devnullfd != STDOUT_FILENO && 485 devnullfd != STDERR_FILENO) { 486 close(devnullfd); 487 devnullfd = -1; 488 } 489} 490 491static isc_boolean_t 492all_digits(const char *s) { 493 if (*s == '\0') 494 return (ISC_FALSE); 495 while (*s != '\0') { 496 if (!isdigit((*s)&0xff)) 497 return (ISC_FALSE); 498 s++; 499 } 500 return (ISC_TRUE); 501} 502 503void 504ns_os_chroot(const char *root) { 505 char strbuf[ISC_STRERRORSIZE]; 506#ifdef HAVE_LIBSCF 507 ns_smf_chroot = 0; 508#endif 509 if (root != NULL) { 510#ifdef HAVE_CHROOT 511 if (chroot(root) < 0) { 512 isc__strerror(errno, strbuf, sizeof(strbuf)); 513 ns_main_earlyfatal("chroot(): %s", strbuf); 514 } 515#else 516 ns_main_earlyfatal("chroot(): disabled"); 517#endif 518 if (chdir("/") < 0) { 519 isc__strerror(errno, strbuf, sizeof(strbuf)); 520 ns_main_earlyfatal("chdir(/): %s", strbuf); 521 } 522#ifdef HAVE_LIBSCF 523 /* Set ns_smf_chroot flag on successful chroot. */ 524 ns_smf_chroot = 1; 525#endif 526 } 527} 528 529void 530ns_os_inituserinfo(const char *username) { 531 char strbuf[ISC_STRERRORSIZE]; 532 if (username == NULL) 533 return; 534 535 if (all_digits(username)) 536 runas_pw = getpwuid((uid_t)atoi(username)); 537 else 538 runas_pw = getpwnam(username); 539 endpwent(); 540 541 if (runas_pw == NULL) 542 ns_main_earlyfatal("user '%s' unknown", username); 543 544 if (getuid() == 0) { 545 if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) { 546 isc__strerror(errno, strbuf, sizeof(strbuf)); 547 ns_main_earlyfatal("initgroups(): %s", strbuf); 548 } 549 } 550 551} 552 553void 554ns_os_changeuser(void) { 555 char strbuf[ISC_STRERRORSIZE]; 556 if (runas_pw == NULL || done_setuid) 557 return; 558 559 done_setuid = ISC_TRUE; 560 561#ifdef HAVE_LINUXTHREADS 562#ifdef HAVE_LINUX_CAPABILITY_H 563 if (!non_root_caps) 564 ns_main_earlyfatal("-u with Linux threads not supported: " 565 "requires kernel support for " 566 "prctl(PR_SET_KEEPCAPS)"); 567#else 568 ns_main_earlyfatal("-u with Linux threads not supported: " 569 "no capabilities support or capabilities " 570 "disabled at build time"); 571#endif 572#endif 573 574 if (setgid(runas_pw->pw_gid) < 0) { 575 isc__strerror(errno, strbuf, sizeof(strbuf)); 576 ns_main_earlyfatal("setgid(): %s", strbuf); 577 } 578 579 if (setuid(runas_pw->pw_uid) < 0) { 580 isc__strerror(errno, strbuf, sizeof(strbuf)); 581 ns_main_earlyfatal("setuid(): %s", strbuf); 582 } 583 584#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) 585 /* 586 * Restore the ability of named to drop core after the setuid() 587 * call has disabled it. 588 */ 589 if (prctl(PR_SET_DUMPABLE,1,0,0,0) < 0) { 590 isc__strerror(errno, strbuf, sizeof(strbuf)); 591 ns_main_earlywarning("prctl(PR_SET_DUMPABLE) failed: %s", 592 strbuf); 593 } 594#endif 595#if defined(HAVE_LINUX_CAPABILITY_H) && !defined(HAVE_LINUXTHREADS) 596 linux_minprivs(); 597#endif 598} 599 600void 601ns_os_adjustnofile() { 602#ifdef HAVE_LINUXTHREADS 603 isc_result_t result; 604 isc_resourcevalue_t newvalue; 605 606 /* 607 * Linux: max number of open files specified by one thread doesn't seem 608 * to apply to other threads on Linux. 609 */ 610 newvalue = ISC_RESOURCE_UNLIMITED; 611 612 result = isc_resource_setlimit(isc_resource_openfiles, newvalue); 613 if (result != ISC_R_SUCCESS) 614 ns_main_earlywarning("couldn't adjust limit on open files"); 615#endif 616} 617 618void 619ns_os_minprivs(void) { 620#ifdef HAVE_SYS_PRCTL_H 621 linux_keepcaps(); 622#endif 623 624#ifdef HAVE_LINUXTHREADS 625 ns_os_changeuser(); /* Call setuid() before threads are started */ 626#endif 627 628#if defined(HAVE_LINUX_CAPABILITY_H) && defined(HAVE_LINUXTHREADS) 629 linux_minprivs(); 630#endif 631} 632 633static int 634safe_open(const char *filename, isc_boolean_t append) { 635 int fd; 636 struct stat sb; 637 638 if (stat(filename, &sb) == -1) { 639 if (errno != ENOENT) 640 return (-1); 641 } else if ((sb.st_mode & S_IFREG) == 0) { 642 errno = EOPNOTSUPP; 643 return (-1); 644 } 645 646 if (append) 647 fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 648 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 649 else { 650 if (unlink(filename) < 0 && errno != ENOENT) 651 return (-1); 652 fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 653 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 654 } 655 return (fd); 656} 657 658static void 659cleanup_pidfile(void) { 660 int n; 661 if (pidfile != NULL) { 662 n = unlink(pidfile); 663 if (n == -1 && errno != ENOENT) 664 ns_main_earlywarning("unlink '%s': failed", pidfile); 665 free(pidfile); 666 } 667 pidfile = NULL; 668} 669 670static int 671mkdirpath(char *filename, void (*report)(const char *, ...)) { 672 char *slash = strrchr(filename, '/'); 673 char strbuf[ISC_STRERRORSIZE]; 674 unsigned int mode; 675 676 if (slash != NULL && slash != filename) { 677 struct stat sb; 678 *slash = '\0'; 679 680 if (stat(filename, &sb) == -1) { 681 if (errno != ENOENT) { 682 isc__strerror(errno, strbuf, sizeof(strbuf)); 683 (*report)("couldn't stat '%s': %s", filename, 684 strbuf); 685 goto error; 686 } 687 if (mkdirpath(filename, report) == -1) 688 goto error; 689 mode = S_IRUSR | S_IWUSR | S_IXUSR; /* u=rwx */ 690 mode |= S_IRGRP | S_IXGRP; /* g=rx */ 691 mode |= S_IROTH | S_IXOTH; /* o=rx */ 692 if (mkdir(filename, mode) == -1) { 693 isc__strerror(errno, strbuf, sizeof(strbuf)); 694 (*report)("couldn't mkdir '%s': %s", filename, 695 strbuf); 696 goto error; 697 } 698 } 699 *slash = '/'; 700 } 701 return (0); 702 703 error: 704 *slash = '/'; 705 return (-1); 706} 707 708void 709ns_os_writepidfile(const char *filename, isc_boolean_t first_time) { 710 int fd; 711 FILE *lockfile; 712 size_t len; 713 pid_t pid; 714 char strbuf[ISC_STRERRORSIZE]; 715 void (*report)(const char *, ...); 716 717 /* 718 * The caller must ensure any required synchronization. 719 */ 720 721 report = first_time ? ns_main_earlyfatal : ns_main_earlywarning; 722 723 cleanup_pidfile(); 724 725 if (filename == NULL) 726 return; 727 728 len = strlen(filename); 729 pidfile = malloc(len + 1); 730 if (pidfile == NULL) { 731 isc__strerror(errno, strbuf, sizeof(strbuf)); 732 (*report)("couldn't malloc '%s': %s", filename, strbuf); 733 return; 734 } 735 736 /* This is safe. */ 737 strcpy(pidfile, filename); 738 739 /* 740 * Make the containing directory if it doesn't exist. 741 */ 742 if (mkdirpath(pidfile, report) == -1) { 743 free(pidfile); 744 pidfile = NULL; 745 return; 746 } 747 748 fd = safe_open(filename, ISC_FALSE); 749 if (fd < 0) { 750 isc__strerror(errno, strbuf, sizeof(strbuf)); 751 (*report)("couldn't open pid file '%s': %s", filename, strbuf); 752 free(pidfile); 753 pidfile = NULL; 754 return; 755 } 756 lockfile = fdopen(fd, "w"); 757 if (lockfile == NULL) { 758 isc__strerror(errno, strbuf, sizeof(strbuf)); 759 (*report)("could not fdopen() pid file '%s': %s", 760 filename, strbuf); 761 (void)close(fd); 762 cleanup_pidfile(); 763 return; 764 } 765#ifdef HAVE_LINUXTHREADS 766 pid = mainpid; 767#else 768 pid = getpid(); 769#endif 770 if (fprintf(lockfile, "%ld\n", (long)pid) < 0) { 771 (*report)("fprintf() to pid file '%s' failed", filename); 772 (void)fclose(lockfile); 773 cleanup_pidfile(); 774 return; 775 } 776 if (fflush(lockfile) == EOF) { 777 (*report)("fflush() to pid file '%s' failed", filename); 778 (void)fclose(lockfile); 779 cleanup_pidfile(); 780 return; 781 } 782 (void)fclose(lockfile); 783} 784 785void 786ns_os_shutdown(void) { 787 closelog(); 788 cleanup_pidfile(); 789} 790 791isc_result_t 792ns_os_gethostname(char *buf, size_t len) { 793 int n; 794 795 n = gethostname(buf, len); 796 return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE); 797} 798 799static char * 800next_token(char **stringp, const char *delim) { 801 char *res; 802 803 do { 804 res = strsep(stringp, delim); 805 if (res == NULL) 806 break; 807 } while (*res == '\0'); 808 return (res); 809} 810 811void 812ns_os_shutdownmsg(char *command, isc_buffer_t *text) { 813 char *input, *ptr; 814 unsigned int n; 815 pid_t pid; 816 817 input = command; 818 819 /* Skip the command name. */ 820 ptr = next_token(&input, " \t"); 821 if (ptr == NULL) 822 return; 823 824 ptr = next_token(&input, " \t"); 825 if (ptr == NULL) 826 return; 827 828 if (strcmp(ptr, "-p") != 0) 829 return; 830 831#ifdef HAVE_LINUXTHREADS 832 pid = mainpid; 833#else 834 pid = getpid(); 835#endif 836 837 n = snprintf((char *)isc_buffer_used(text), 838 isc_buffer_availablelength(text), 839 "pid: %ld", (long)pid); 840 /* Only send a message if it is complete. */ 841 if (n < isc_buffer_availablelength(text)) 842 isc_buffer_add(text, n); 843} 844 845void 846ns_os_tzset(void) { 847#ifdef HAVE_TZSET 848 tzset(); 849#endif 850} 851