1/* 2 * Copyright (C) 2004, 2005, 2007-2009, 2012 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.37.360.2 2012/02/06 23:45:57 tbox Exp $ */ 19 20#include <config.h> 21#include <stdarg.h> 22 23#include <sys/types.h> 24#include <sys/stat.h> 25 26#include <ctype.h> 27#include <errno.h> 28#include <io.h> 29#include <process.h> 30#include <fcntl.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <syslog.h> 34 35#include <isc/print.h> 36#include <isc/result.h> 37#include <isc/strerror.h> 38#include <isc/string.h> 39#include <isc/ntpaths.h> 40#include <isc/util.h> 41#include <isc/win32os.h> 42 43#include <named/main.h> 44#include <named/log.h> 45#include <named/os.h> 46#include <named/globals.h> 47#include <named/ntservice.h> 48 49 50static char *pidfile = NULL; 51static int devnullfd = -1; 52 53static BOOL Initialized = FALSE; 54 55static char *version_error = 56 "named requires Windows 2000 Service Pack 2 or later to run correctly"; 57 58void 59ns_paths_init() { 60 if (!Initialized) 61 isc_ntpaths_init(); 62 63 ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH); 64 lwresd_g_conffile = isc_ntpaths_get(LWRES_CONF_PATH); 65 lwresd_g_resolvconffile = isc_ntpaths_get(RESOLV_CONF_PATH); 66 ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH); 67 ns_g_defaultpidfile = isc_ntpaths_get(NAMED_PID_PATH); 68 lwresd_g_defaultpidfile = isc_ntpaths_get(LWRESD_PID_PATH); 69 ns_g_keyfile = isc_ntpaths_get(RNDC_KEY_PATH); 70 ns_g_defaultsessionkeyfile = isc_ntpaths_get(SESSION_KEY_PATH); 71 72 Initialized = TRUE; 73} 74 75/* 76 * Due to Knowledge base article Q263823 we need to make sure that 77 * Windows 2000 systems have Service Pack 2 or later installed and 78 * warn when it isn't. 79 */ 80static void 81version_check(const char *progname) { 82 83 if(isc_win32os_majorversion() < 5) 84 return; /* No problem with Version 4.0 */ 85 if(isc_win32os_versioncheck(5, 0, 2, 0) < 0) 86 if (ntservice_isservice()) 87 NTReportError(progname, version_error); 88 else 89 fprintf(stderr, "%s\n", version_error); 90} 91 92static void 93setup_syslog(const char *progname) { 94 int options; 95 96 options = LOG_PID; 97#ifdef LOG_NDELAY 98 options |= LOG_NDELAY; 99#endif 100 101 openlog(progname, options, LOG_DAEMON); 102} 103 104void 105ns_os_init(const char *progname) { 106 ns_paths_init(); 107 setup_syslog(progname); 108 /* 109 * XXXMPA. We may need to split ntservice_init() in two and 110 * just mark as running in ns_os_started(). If we do that 111 * this is where the first part of ntservice_init() should be 112 * called from. 113 * 114 * XXX970 Remove comment if no problems by 9.7.0. 115 * 116 * ntservice_init(); 117 */ 118 version_check(progname); 119} 120 121void 122ns_os_daemonize(void) { 123 /* 124 * Try to set stdin, stdout, and stderr to /dev/null, but press 125 * on even if it fails. 126 */ 127 if (devnullfd != -1) { 128 if (devnullfd != _fileno(stdin)) { 129 close(_fileno(stdin)); 130 (void)_dup2(devnullfd, _fileno(stdin)); 131 } 132 if (devnullfd != _fileno(stdout)) { 133 close(_fileno(stdout)); 134 (void)_dup2(devnullfd, _fileno(stdout)); 135 } 136 if (devnullfd != _fileno(stderr)) { 137 close(_fileno(stderr)); 138 (void)_dup2(devnullfd, _fileno(stderr)); 139 } 140 } 141} 142 143void 144ns_os_opendevnull(void) { 145 devnullfd = open("NUL", O_RDWR, 0); 146} 147 148void 149ns_os_closedevnull(void) { 150 if (devnullfd != _fileno(stdin) && 151 devnullfd != _fileno(stdout) && 152 devnullfd != _fileno(stderr)) { 153 close(devnullfd); 154 devnullfd = -1; 155 } 156} 157 158void 159ns_os_chroot(const char *root) { 160 if (root != NULL) 161 ns_main_earlyfatal("chroot(): isn't supported by Win32 API"); 162} 163 164void 165ns_os_inituserinfo(const char *username) { 166} 167 168void 169ns_os_changeuser(void) { 170} 171 172void 173ns_os_adjustnofile(void) { 174} 175 176void 177ns_os_minprivs(void) { 178} 179 180static int 181safe_open(const char *filename, int mode, isc_boolean_t append) { 182 int fd; 183 struct stat sb; 184 185 if (stat(filename, &sb) == -1) { 186 if (errno != ENOENT) 187 return (-1); 188 } else if ((sb.st_mode & S_IFREG) == 0) 189 return (-1); 190 191 if (append) 192 fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, mode); 193 else { 194 (void)unlink(filename); 195 fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, mode); 196 } 197 return (fd); 198} 199 200static void 201cleanup_pidfile(void) { 202 if (pidfile != NULL) { 203 (void)unlink(pidfile); 204 free(pidfile); 205 } 206 pidfile = NULL; 207} 208 209FILE * 210ns_os_openfile(const char *filename, int mode, isc_boolean_t switch_user) { 211 char strbuf[ISC_STRERRORSIZE]; 212 FILE *fp; 213 int fd; 214 215 UNUSED(switch_user); 216 fd = safe_open(filename, mode, ISC_FALSE); 217 if (fd < 0) { 218 isc__strerror(errno, strbuf, sizeof(strbuf)); 219 ns_main_earlywarning("could not open file '%s': %s", 220 filename, strbuf); 221 return (NULL); 222 } 223 224 fp = fdopen(fd, "w"); 225 if (fp == NULL) { 226 isc__strerror(errno, strbuf, sizeof(strbuf)); 227 ns_main_earlywarning("could not fdopen() file '%s': %s", 228 filename, strbuf); 229 close(fd); 230 } 231 232 return (fp); 233} 234 235void 236ns_os_writepidfile(const char *filename, isc_boolean_t first_time) { 237 FILE *lockfile; 238 pid_t pid; 239 char strbuf[ISC_STRERRORSIZE]; 240 void (*report)(const char *, ...); 241 242 /* 243 * The caller must ensure any required synchronization. 244 */ 245 246 report = first_time ? ns_main_earlyfatal : ns_main_earlywarning; 247 248 cleanup_pidfile(); 249 250 if (filename == NULL) 251 return; 252 253 pidfile = strdup(filename); 254 if (pidfile == NULL) { 255 isc__strerror(errno, strbuf, sizeof(strbuf)); 256 (*report)("couldn't strdup() '%s': %s", filename, strbuf); 257 return; 258 } 259 260 lockfile = ns_os_openfile(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 261 ISC_FALSE); 262 if (lockfile == NULL) { 263 free(pidfile); 264 pidfile = NULL; 265 return; 266 } 267 268 pid = getpid(); 269 270 if (fprintf(lockfile, "%ld\n", (long)pid) < 0) { 271 (*report)("fprintf() to pid file '%s' failed", filename); 272 (void)fclose(lockfile); 273 cleanup_pidfile(); 274 return; 275 } 276 if (fflush(lockfile) == EOF) { 277 (*report)("fflush() to pid file '%s' failed", filename); 278 (void)fclose(lockfile); 279 cleanup_pidfile(); 280 return; 281 } 282 (void)fclose(lockfile); 283} 284 285void 286ns_os_shutdown(void) { 287 closelog(); 288 cleanup_pidfile(); 289 ntservice_shutdown(); /* This MUST be the last thing done */ 290} 291 292isc_result_t 293ns_os_gethostname(char *buf, size_t len) { 294 int n; 295 296 n = gethostname(buf, len); 297 return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE); 298} 299 300void 301ns_os_shutdownmsg(char *command, isc_buffer_t *text) { 302 UNUSED(command); 303 UNUSED(text); 304} 305 306void 307ns_os_tzset(void) { 308#ifdef HAVE_TZSET 309 tzset(); 310#endif 311} 312 313void 314ns_os_started(void) { 315 ntservice_init(); 316} 317