00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021 #include <stdarg.h>
00022
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025
00026 #include <ctype.h>
00027 #include <errno.h>
00028 #include <fcntl.h>
00029 #include <grp.h>
00030 #include <pwd.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <signal.h>
00034 #include <syslog.h>
00035 #ifdef HAVE_TZSET
00036 #include <time.h>
00037 #endif
00038 #include <unistd.h>
00039
00040 #include <isc/buffer.h>
00041 #include <isc/file.h>
00042 #include <isc/print.h>
00043 #include <isc/resource.h>
00044 #include <isc/result.h>
00045 #include <isc/strerror.h>
00046 #include <isc/string.h>
00047
00048 #include <named/main.h>
00049 #include <named/os.h>
00050 #ifdef HAVE_LIBSCF
00051 #include <named/ns_smf_globals.h>
00052 #endif
00053
00054 static char *pidfile = NULL;
00055 static char *lockfile = NULL;
00056 static int devnullfd = -1;
00057 static int singletonfd = -1;
00058
00059 #ifndef ISC_FACILITY
00060 #define ISC_FACILITY LOG_DAEMON
00061 #endif
00062
00063
00064
00065
00066 #ifndef HAVE_LINUX_CAPABILITY_H
00067 #undef HAVE_SYS_PRCTL_H
00068 #endif
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 #ifdef HAVE_LINUXTHREADS
00108 static pid_t mainpid = 0;
00109 #endif
00110
00111 static struct passwd *runas_pw = NULL;
00112 static isc_boolean_t done_setuid = ISC_FALSE;
00113 static int dfd[2] = { -1, -1 };
00114
00115 #ifdef HAVE_LINUX_CAPABILITY_H
00116
00117 static isc_boolean_t non_root = ISC_FALSE;
00118 static isc_boolean_t non_root_caps = ISC_FALSE;
00119
00120 #ifdef HAVE_SYS_CAPABILITY_H
00121 #include <sys/capability.h>
00122 #else
00123 #ifdef HAVE_LINUX_TYPES_H
00124 #include <linux/types.h>
00125 #endif
00126
00127
00128
00129
00130
00131
00132 #define _LINUX_FS_H
00133 #include <linux/capability.h>
00134 #include <syscall.h>
00135 #ifndef SYS_capset
00136 #ifndef __NR_capset
00137 #include <asm/unistd.h>
00138 #endif
00139 #define SYS_capset __NR_capset
00140 #endif
00141 #endif
00142
00143 #ifdef HAVE_SYS_PRCTL_H
00144 #include <sys/prctl.h>
00145
00146
00147
00148
00149
00150
00151
00152 #ifndef PR_SET_KEEPCAPS
00153 #define PR_SET_KEEPCAPS 8
00154 #endif
00155
00156 #endif
00157
00158 #ifdef HAVE_LIBCAP
00159 #define SETCAPS_FUNC "cap_set_proc "
00160 #else
00161 typedef unsigned int cap_t;
00162 #define SETCAPS_FUNC "syscall(capset) "
00163 #endif
00164
00165 static void
00166 linux_setcaps(cap_t caps) {
00167 #ifndef HAVE_LIBCAP
00168 struct __user_cap_header_struct caphead;
00169 struct __user_cap_data_struct cap;
00170 #endif
00171 char strbuf[ISC_STRERRORSIZE];
00172
00173 if ((getuid() != 0 && !non_root_caps) || non_root)
00174 return;
00175 #ifndef HAVE_LIBCAP
00176 memset(&caphead, 0, sizeof(caphead));
00177 caphead.version = _LINUX_CAPABILITY_VERSION;
00178 caphead.pid = 0;
00179 memset(&cap, 0, sizeof(cap));
00180 cap.effective = caps;
00181 cap.permitted = caps;
00182 cap.inheritable = 0;
00183 #endif
00184 #ifdef HAVE_LIBCAP
00185 if (cap_set_proc(caps) < 0) {
00186 #else
00187 if (syscall(SYS_capset, &caphead, &cap) < 0) {
00188 #endif
00189 isc__strerror(errno, strbuf, sizeof(strbuf));
00190 ns_main_earlyfatal(SETCAPS_FUNC "failed: %s:"
00191 " please ensure that the capset kernel"
00192 " module is loaded. see insmod(8)",
00193 strbuf);
00194 }
00195 }
00196
00197 #ifdef HAVE_LIBCAP
00198 #define SET_CAP(flag) \
00199 do { \
00200 cap_flag_value_t curval; \
00201 capval = (flag); \
00202 err = cap_get_flag(curcaps, capval, CAP_PERMITTED, &curval); \
00203 if (err != -1 && curval) { \
00204 err = cap_set_flag(caps, CAP_EFFECTIVE, 1, &capval, CAP_SET); \
00205 if (err == -1) { \
00206 isc__strerror(errno, strbuf, sizeof(strbuf)); \
00207 ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \
00208 } \
00209 \
00210 err = cap_set_flag(caps, CAP_PERMITTED, 1, &capval, CAP_SET); \
00211 if (err == -1) { \
00212 isc__strerror(errno, strbuf, sizeof(strbuf)); \
00213 ns_main_earlyfatal("cap_set_proc failed: %s", strbuf); \
00214 } \
00215 } \
00216 } while (0)
00217 #define INIT_CAP \
00218 do { \
00219 caps = cap_init(); \
00220 if (caps == NULL) { \
00221 isc__strerror(errno, strbuf, sizeof(strbuf)); \
00222 ns_main_earlyfatal("cap_init failed: %s", strbuf); \
00223 } \
00224 curcaps = cap_get_proc(); \
00225 if (curcaps == NULL) { \
00226 isc__strerror(errno, strbuf, sizeof(strbuf)); \
00227 ns_main_earlyfatal("cap_get_proc failed: %s", strbuf); \
00228 } \
00229 } while (0)
00230 #define FREE_CAP \
00231 { \
00232 cap_free(caps); \
00233 cap_free(curcaps); \
00234 } while (0)
00235 #else
00236 #define SET_CAP(flag) do { caps |= (1 << (flag)); } while (0)
00237 #define INIT_CAP do { caps = 0; } while (0)
00238 #endif
00239
00240 static void
00241 linux_initialprivs(void) {
00242 cap_t caps;
00243 #ifdef HAVE_LIBCAP
00244 cap_t curcaps;
00245 cap_value_t capval;
00246 char strbuf[ISC_STRERRORSIZE];
00247 int err;
00248 #endif
00249
00250
00251
00252
00253
00254
00255 INIT_CAP;
00256
00257
00258
00259
00260 SET_CAP(CAP_NET_BIND_SERVICE);
00261
00262
00263
00264
00265 SET_CAP(CAP_SYS_CHROOT);
00266
00267 #if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS)
00268
00269
00270
00271
00272
00273
00274 SET_CAP(CAP_SETUID);
00275 #endif
00276
00277
00278
00279
00280 SET_CAP(CAP_SETGID);
00281
00282
00283
00284
00285
00286 SET_CAP(CAP_DAC_READ_SEARCH);
00287
00288
00289
00290
00291
00292
00293
00294
00295 SET_CAP(CAP_SYS_RESOURCE);
00296
00297
00298
00299
00300
00301 SET_CAP(CAP_CHOWN);
00302
00303 linux_setcaps(caps);
00304
00305 #ifdef HAVE_LIBCAP
00306 FREE_CAP;
00307 #endif
00308 }
00309
00310 static void
00311 linux_minprivs(void) {
00312 cap_t caps;
00313 #ifdef HAVE_LIBCAP
00314 cap_t curcaps;
00315 cap_value_t capval;
00316 char strbuf[ISC_STRERRORSIZE];
00317 int err;
00318 #endif
00319
00320 INIT_CAP;
00321
00322
00323
00324
00325
00326
00327
00328
00329 SET_CAP(CAP_NET_BIND_SERVICE);
00330
00331
00332
00333
00334
00335
00336
00337
00338 SET_CAP(CAP_SYS_RESOURCE);
00339
00340 linux_setcaps(caps);
00341
00342 #ifdef HAVE_LIBCAP
00343 FREE_CAP;
00344 #endif
00345 }
00346
00347 #ifdef HAVE_SYS_PRCTL_H
00348 static void
00349 linux_keepcaps(void) {
00350 char strbuf[ISC_STRERRORSIZE];
00351
00352
00353
00354
00355
00356 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
00357 if (errno != EINVAL) {
00358 isc__strerror(errno, strbuf, sizeof(strbuf));
00359 ns_main_earlyfatal("prctl() failed: %s", strbuf);
00360 }
00361 } else {
00362 non_root_caps = ISC_TRUE;
00363 if (getuid() != 0)
00364 non_root = ISC_TRUE;
00365 }
00366 }
00367 #endif
00368
00369 #endif
00370
00371
00372 static void
00373 setup_syslog(const char *progname) {
00374 int options;
00375
00376 options = LOG_PID;
00377 #ifdef LOG_NDELAY
00378 options |= LOG_NDELAY;
00379 #endif
00380 openlog(isc_file_basename(progname), options, ISC_FACILITY);
00381 }
00382
00383 void
00384 ns_os_init(const char *progname) {
00385 setup_syslog(progname);
00386 #ifdef HAVE_LINUX_CAPABILITY_H
00387 linux_initialprivs();
00388 #endif
00389 #ifdef HAVE_LINUXTHREADS
00390 mainpid = getpid();
00391 #endif
00392 #ifdef SIGXFSZ
00393 signal(SIGXFSZ, SIG_IGN);
00394 #endif
00395 }
00396
00397 void
00398 ns_os_daemonize(void) {
00399 pid_t pid;
00400 char strbuf[ISC_STRERRORSIZE];
00401
00402 if (pipe(dfd) == -1) {
00403 isc__strerror(errno, strbuf, sizeof(strbuf));
00404 ns_main_earlyfatal("pipe(): %s", strbuf);
00405 }
00406
00407 pid = fork();
00408 if (pid == -1) {
00409 isc__strerror(errno, strbuf, sizeof(strbuf));
00410 ns_main_earlyfatal("fork(): %s", strbuf);
00411 }
00412 if (pid != 0) {
00413 int n;
00414
00415
00416
00417
00418
00419 (void)close(dfd[1]);
00420 do {
00421 char buf;
00422 n = read(dfd[0], &buf, 1);
00423 if (n == 1)
00424 _exit(0);
00425 } while (n == -1 && errno == EINTR);
00426 _exit(1);
00427 }
00428 (void)close(dfd[0]);
00429
00430
00431
00432
00433
00434 #ifdef HAVE_LINUXTHREADS
00435 mainpid = getpid();
00436 #endif
00437
00438 if (setsid() == -1) {
00439 isc__strerror(errno, strbuf, sizeof(strbuf));
00440 ns_main_earlyfatal("setsid(): %s", strbuf);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 if (devnullfd != -1) {
00454 if (devnullfd != STDIN_FILENO) {
00455 (void)close(STDIN_FILENO);
00456 (void)dup2(devnullfd, STDIN_FILENO);
00457 }
00458 if (devnullfd != STDOUT_FILENO) {
00459 (void)close(STDOUT_FILENO);
00460 (void)dup2(devnullfd, STDOUT_FILENO);
00461 }
00462 if (devnullfd != STDERR_FILENO) {
00463 (void)close(STDERR_FILENO);
00464 (void)dup2(devnullfd, STDERR_FILENO);
00465 }
00466 }
00467 }
00468
00469 void
00470 ns_os_started(void) {
00471 char buf = 0;
00472
00473
00474
00475
00476 if (dfd[0] != -1 && dfd[1] != -1) {
00477 if (write(dfd[1], &buf, 1) != 1)
00478 ns_main_earlyfatal("unable to signal parent that we "
00479 "otherwise started successfully.");
00480 close(dfd[1]);
00481 dfd[0] = dfd[1] = -1;
00482 }
00483 }
00484
00485 void
00486 ns_os_opendevnull(void) {
00487 devnullfd = open("/dev/null", O_RDWR, 0);
00488 }
00489
00490 void
00491 ns_os_closedevnull(void) {
00492 if (devnullfd != STDIN_FILENO &&
00493 devnullfd != STDOUT_FILENO &&
00494 devnullfd != STDERR_FILENO) {
00495 close(devnullfd);
00496 devnullfd = -1;
00497 }
00498 }
00499
00500 static isc_boolean_t
00501 all_digits(const char *s) {
00502 if (*s == '\0')
00503 return (ISC_FALSE);
00504 while (*s != '\0') {
00505 if (!isdigit((*s)&0xff))
00506 return (ISC_FALSE);
00507 s++;
00508 }
00509 return (ISC_TRUE);
00510 }
00511
00512 void
00513 ns_os_chroot(const char *root) {
00514 char strbuf[ISC_STRERRORSIZE];
00515 #ifdef HAVE_LIBSCF
00516 ns_smf_chroot = 0;
00517 #endif
00518 if (root != NULL) {
00519 #ifdef HAVE_CHROOT
00520 if (chroot(root) < 0) {
00521 isc__strerror(errno, strbuf, sizeof(strbuf));
00522 ns_main_earlyfatal("chroot(): %s", strbuf);
00523 }
00524 #else
00525 ns_main_earlyfatal("chroot(): disabled");
00526 #endif
00527 if (chdir("/") < 0) {
00528 isc__strerror(errno, strbuf, sizeof(strbuf));
00529 ns_main_earlyfatal("chdir(/): %s", strbuf);
00530 }
00531 #ifdef HAVE_LIBSCF
00532
00533 ns_smf_chroot = 1;
00534 #endif
00535 }
00536 }
00537
00538 void
00539 ns_os_inituserinfo(const char *username) {
00540 char strbuf[ISC_STRERRORSIZE];
00541 if (username == NULL)
00542 return;
00543
00544 if (all_digits(username))
00545 runas_pw = getpwuid((uid_t)atoi(username));
00546 else
00547 runas_pw = getpwnam(username);
00548 endpwent();
00549
00550 if (runas_pw == NULL)
00551 ns_main_earlyfatal("user '%s' unknown", username);
00552
00553 if (getuid() == 0) {
00554 if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) {
00555 isc__strerror(errno, strbuf, sizeof(strbuf));
00556 ns_main_earlyfatal("initgroups(): %s", strbuf);
00557 }
00558 }
00559
00560 }
00561
00562 void
00563 ns_os_changeuser(void) {
00564 char strbuf[ISC_STRERRORSIZE];
00565 if (runas_pw == NULL || done_setuid)
00566 return;
00567
00568 done_setuid = ISC_TRUE;
00569
00570 #ifdef HAVE_LINUXTHREADS
00571 #ifdef HAVE_LINUX_CAPABILITY_H
00572 if (!non_root_caps)
00573 ns_main_earlyfatal("-u with Linux threads not supported: "
00574 "requires kernel support for "
00575 "prctl(PR_SET_KEEPCAPS)");
00576 #else
00577 ns_main_earlyfatal("-u with Linux threads not supported: "
00578 "no capabilities support or capabilities "
00579 "disabled at build time");
00580 #endif
00581 #endif
00582
00583 if (setgid(runas_pw->pw_gid) < 0) {
00584 isc__strerror(errno, strbuf, sizeof(strbuf));
00585 ns_main_earlyfatal("setgid(): %s", strbuf);
00586 }
00587
00588 if (setuid(runas_pw->pw_uid) < 0) {
00589 isc__strerror(errno, strbuf, sizeof(strbuf));
00590 ns_main_earlyfatal("setuid(): %s", strbuf);
00591 }
00592
00593 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
00594
00595
00596
00597
00598 if (prctl(PR_SET_DUMPABLE,1,0,0,0) < 0) {
00599 isc__strerror(errno, strbuf, sizeof(strbuf));
00600 ns_main_earlywarning("prctl(PR_SET_DUMPABLE) failed: %s",
00601 strbuf);
00602 }
00603 #endif
00604 #if defined(HAVE_LINUX_CAPABILITY_H) && !defined(HAVE_LINUXTHREADS)
00605 linux_minprivs();
00606 #endif
00607 }
00608
00609 void
00610 ns_os_adjustnofile(void) {
00611 #ifdef HAVE_LINUXTHREADS
00612 isc_result_t result;
00613 isc_resourcevalue_t newvalue;
00614
00615
00616
00617
00618
00619 newvalue = ISC_RESOURCE_UNLIMITED;
00620
00621 result = isc_resource_setlimit(isc_resource_openfiles, newvalue);
00622 if (result != ISC_R_SUCCESS)
00623 ns_main_earlywarning("couldn't adjust limit on open files");
00624 #endif
00625 }
00626
00627 void
00628 ns_os_minprivs(void) {
00629 #ifdef HAVE_SYS_PRCTL_H
00630 linux_keepcaps();
00631 #endif
00632
00633 #ifdef HAVE_LINUXTHREADS
00634 ns_os_changeuser();
00635 #endif
00636
00637 #if defined(HAVE_LINUX_CAPABILITY_H) && defined(HAVE_LINUXTHREADS)
00638 linux_minprivs();
00639 #endif
00640 }
00641
00642 static int
00643 safe_open(const char *filename, mode_t mode, isc_boolean_t append) {
00644 int fd;
00645 struct stat sb;
00646
00647 if (stat(filename, &sb) == -1) {
00648 if (errno != ENOENT)
00649 return (-1);
00650 } else if ((sb.st_mode & S_IFREG) == 0) {
00651 errno = EOPNOTSUPP;
00652 return (-1);
00653 }
00654
00655 if (append)
00656 fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, mode);
00657 else {
00658 if (unlink(filename) < 0 && errno != ENOENT)
00659 return (-1);
00660 fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
00661 }
00662 return (fd);
00663 }
00664
00665 static void
00666 cleanup_pidfile(void) {
00667 int n;
00668 if (pidfile != NULL) {
00669 n = unlink(pidfile);
00670 if (n == -1 && errno != ENOENT)
00671 ns_main_earlywarning("unlink '%s': failed", pidfile);
00672 free(pidfile);
00673 }
00674 pidfile = NULL;
00675 }
00676
00677 static void
00678 cleanup_lockfile(void) {
00679 if (singletonfd != -1) {
00680 close(singletonfd);
00681 singletonfd = -1;
00682 }
00683
00684 if (lockfile != NULL) {
00685 int n = unlink(lockfile);
00686 if (n == -1 && errno != ENOENT)
00687 ns_main_earlywarning("unlink '%s': failed", lockfile);
00688 free(lockfile);
00689 lockfile = NULL;
00690 }
00691 }
00692
00693
00694
00695
00696
00697
00698 static int
00699 mkdirpath(char *filename, void (*report)(const char *, ...)) {
00700 char *slash = strrchr(filename, '/');
00701 char strbuf[ISC_STRERRORSIZE];
00702 unsigned int mode;
00703
00704 if (slash != NULL && slash != filename) {
00705 struct stat sb;
00706 *slash = '\0';
00707
00708 if (stat(filename, &sb) == -1) {
00709 if (errno != ENOENT) {
00710 isc__strerror(errno, strbuf, sizeof(strbuf));
00711 (*report)("couldn't stat '%s': %s", filename,
00712 strbuf);
00713 goto error;
00714 }
00715 if (mkdirpath(filename, report) == -1)
00716 goto error;
00717
00718
00719
00720 if (!strcmp(slash + 1, "") ||
00721 !strcmp(slash + 1, ".") ||
00722 !strcmp(slash + 1, "..")) {
00723 *slash = '/';
00724 return (0);
00725 }
00726 mode = S_IRUSR | S_IWUSR | S_IXUSR;
00727 mode |= S_IRGRP | S_IXGRP;
00728 mode |= S_IROTH | S_IXOTH;
00729 if (mkdir(filename, mode) == -1) {
00730 isc__strerror(errno, strbuf, sizeof(strbuf));
00731 (*report)("couldn't mkdir '%s': %s", filename,
00732 strbuf);
00733 goto error;
00734 }
00735 if (runas_pw != NULL &&
00736 chown(filename, runas_pw->pw_uid,
00737 runas_pw->pw_gid) == -1) {
00738 isc__strerror(errno, strbuf, sizeof(strbuf));
00739 (*report)("couldn't chown '%s': %s", filename,
00740 strbuf);
00741 }
00742 }
00743 *slash = '/';
00744 }
00745 return (0);
00746
00747 error:
00748 *slash = '/';
00749 return (-1);
00750 }
00751
00752 static void
00753 setperms(uid_t uid, gid_t gid) {
00754 char strbuf[ISC_STRERRORSIZE];
00755 #if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
00756 gid_t oldgid, tmpg;
00757 #endif
00758 #if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID)
00759 uid_t olduid, tmpu;
00760 #endif
00761 #if defined(HAVE_SETEGID)
00762 if (getegid() != gid && setegid(gid) == -1) {
00763 isc__strerror(errno, strbuf, sizeof(strbuf));
00764 ns_main_earlywarning("unable to set effective gid to %ld: %s",
00765 (long)gid, strbuf);
00766 }
00767 #elif defined(HAVE_SETRESGID)
00768 if (getresgid(&tmpg, &oldgid, &tmpg) == -1 || oldgid != gid) {
00769 if (setresgid(-1, gid, -1) == -1) {
00770 isc__strerror(errno, strbuf, sizeof(strbuf));
00771 ns_main_earlywarning("unable to set effective "
00772 "gid to %d: %s", gid, strbuf);
00773 }
00774 }
00775 #endif
00776
00777 #if defined(HAVE_SETEUID)
00778 if (geteuid() != uid && seteuid(uid) == -1) {
00779 isc__strerror(errno, strbuf, sizeof(strbuf));
00780 ns_main_earlywarning("unable to set effective uid to %ld: %s",
00781 (long)uid, strbuf);
00782 }
00783 #elif defined(HAVE_SETRESUID)
00784 if (getresuid(&tmpu, &olduid, &tmpu) == -1 || olduid != uid) {
00785 if (setresuid(-1, uid, -1) == -1) {
00786 isc__strerror(errno, strbuf, sizeof(strbuf));
00787 ns_main_earlywarning("unable to set effective "
00788 "uid to %d: %s", uid, strbuf);
00789 }
00790 }
00791 #endif
00792 }
00793
00794 FILE *
00795 ns_os_openfile(const char *filename, mode_t mode, isc_boolean_t switch_user) {
00796 char strbuf[ISC_STRERRORSIZE], *f;
00797 FILE *fp;
00798 int fd;
00799
00800
00801
00802
00803 f = strdup(filename);
00804 if (f == NULL) {
00805 isc__strerror(errno, strbuf, sizeof(strbuf));
00806 ns_main_earlywarning("couldn't strdup() '%s': %s",
00807 filename, strbuf);
00808 return (NULL);
00809 }
00810 if (mkdirpath(f, ns_main_earlywarning) == -1) {
00811 free(f);
00812 return (NULL);
00813 }
00814 free(f);
00815
00816 if (switch_user && runas_pw != NULL) {
00817 #ifndef HAVE_LINUXTHREADS
00818 gid_t oldgid = getgid();
00819 #endif
00820
00821 setperms(runas_pw->pw_uid, runas_pw->pw_gid);
00822
00823 fd = safe_open(filename, mode, ISC_FALSE);
00824
00825 #ifndef HAVE_LINUXTHREADS
00826
00827 setperms(0, oldgid);
00828 #endif
00829
00830 if (fd == -1) {
00831 #ifndef HAVE_LINUXTHREADS
00832 fd = safe_open(filename, mode, ISC_FALSE);
00833 if (fd != -1) {
00834 ns_main_earlywarning("Required root "
00835 "permissions to open "
00836 "'%s'.", filename);
00837 } else {
00838 ns_main_earlywarning("Could not open "
00839 "'%s'.", filename);
00840 }
00841 ns_main_earlywarning("Please check file and "
00842 "directory permissions "
00843 "or reconfigure the filename.");
00844 #else
00845 ns_main_earlywarning("Could not open "
00846 "'%s'.", filename);
00847 ns_main_earlywarning("Please check file and "
00848 "directory permissions "
00849 "or reconfigure the filename.");
00850 #endif
00851 }
00852 } else {
00853 fd = safe_open(filename, mode, ISC_FALSE);
00854 }
00855
00856 if (fd < 0) {
00857 isc__strerror(errno, strbuf, sizeof(strbuf));
00858 ns_main_earlywarning("could not open file '%s': %s",
00859 filename, strbuf);
00860 return (NULL);
00861 }
00862
00863 fp = fdopen(fd, "w");
00864 if (fp == NULL) {
00865 isc__strerror(errno, strbuf, sizeof(strbuf));
00866 ns_main_earlywarning("could not fdopen() file '%s': %s",
00867 filename, strbuf);
00868 }
00869
00870 return (fp);
00871 }
00872
00873 void
00874 ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
00875 FILE *fh;
00876 pid_t pid;
00877 char strbuf[ISC_STRERRORSIZE];
00878 void (*report)(const char *, ...);
00879
00880
00881
00882
00883
00884 report = first_time ? ns_main_earlyfatal : ns_main_earlywarning;
00885
00886 cleanup_pidfile();
00887
00888 if (filename == NULL)
00889 return;
00890
00891 pidfile = strdup(filename);
00892 if (pidfile == NULL) {
00893 isc__strerror(errno, strbuf, sizeof(strbuf));
00894 (*report)("couldn't strdup() '%s': %s", filename, strbuf);
00895 return;
00896 }
00897
00898 fh = ns_os_openfile(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
00899 first_time);
00900 if (fh == NULL) {
00901 cleanup_pidfile();
00902 return;
00903 }
00904 #ifdef HAVE_LINUXTHREADS
00905 pid = mainpid;
00906 #else
00907 pid = getpid();
00908 #endif
00909 if (fprintf(fh, "%ld\n", (long)pid) < 0) {
00910 (*report)("fprintf() to pid file '%s' failed", filename);
00911 (void)fclose(fh);
00912 cleanup_pidfile();
00913 return;
00914 }
00915 if (fflush(fh) == EOF) {
00916 (*report)("fflush() to pid file '%s' failed", filename);
00917 (void)fclose(fh);
00918 cleanup_pidfile();
00919 return;
00920 }
00921 (void)fclose(fh);
00922 }
00923
00924 isc_boolean_t
00925 ns_os_issingleton(const char *filename) {
00926 char strbuf[ISC_STRERRORSIZE];
00927 struct flock lock;
00928
00929 if (singletonfd != -1)
00930 return (ISC_TRUE);
00931
00932 if (strcasecmp(filename, "none") == 0)
00933 return (ISC_TRUE);
00934
00935
00936
00937
00938 lockfile = strdup(filename);
00939 if (lockfile == NULL) {
00940 isc__strerror(errno, strbuf, sizeof(strbuf));
00941 ns_main_earlyfatal("couldn't allocate memory for '%s': %s",
00942 filename, strbuf);
00943 } else {
00944 int ret = mkdirpath(lockfile, ns_main_earlywarning);
00945 if (ret == -1) {
00946 ns_main_earlywarning("couldn't create '%s'", filename);
00947 cleanup_lockfile();
00948 return (ISC_FALSE);
00949 }
00950 }
00951
00952
00953
00954
00955
00956 singletonfd = open(filename, O_WRONLY | O_CREAT,
00957 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
00958 if (singletonfd == -1) {
00959 cleanup_lockfile();
00960 return (ISC_FALSE);
00961 }
00962
00963 memset(&lock, 0, sizeof(lock));
00964 lock.l_type = F_WRLCK;
00965 lock.l_whence = SEEK_SET;
00966 lock.l_start = 0;
00967 lock.l_len = 1;
00968
00969
00970 if (fcntl(singletonfd, F_SETLK, &lock) == -1) {
00971 close(singletonfd);
00972 singletonfd = -1;
00973 return (ISC_FALSE);
00974 }
00975
00976 return (ISC_TRUE);
00977 }
00978
00979 void
00980 ns_os_shutdown(void) {
00981 closelog();
00982 cleanup_pidfile();
00983 cleanup_lockfile();
00984 }
00985
00986 isc_result_t
00987 ns_os_gethostname(char *buf, size_t len) {
00988 int n;
00989
00990 n = gethostname(buf, len);
00991 return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE);
00992 }
00993
00994 static char *
00995 next_token(char **stringp, const char *delim) {
00996 char *res;
00997
00998 do {
00999 res = strsep(stringp, delim);
01000 if (res == NULL)
01001 break;
01002 } while (*res == '\0');
01003 return (res);
01004 }
01005
01006 void
01007 ns_os_shutdownmsg(char *command, isc_buffer_t *text) {
01008 char *input, *ptr;
01009 unsigned int n;
01010 pid_t pid;
01011
01012 input = command;
01013
01014
01015 ptr = next_token(&input, " \t");
01016 if (ptr == NULL)
01017 return;
01018
01019 ptr = next_token(&input, " \t");
01020 if (ptr == NULL)
01021 return;
01022
01023 if (strcmp(ptr, "-p") != 0)
01024 return;
01025
01026 #ifdef HAVE_LINUXTHREADS
01027 pid = mainpid;
01028 #else
01029 pid = getpid();
01030 #endif
01031
01032 n = snprintf((char *)isc_buffer_used(text),
01033 isc_buffer_availablelength(text),
01034 "pid: %ld", (long)pid);
01035
01036 if (n > 0 && n < isc_buffer_availablelength(text))
01037 isc_buffer_add(text, n);
01038 }
01039
01040 void
01041 ns_os_tzset(void) {
01042 #ifdef HAVE_TZSET
01043 tzset();
01044 #endif
01045 }