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