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