os.c 7.67 KB
Newer Older
Danny Mayer's avatar
Danny Mayer committed
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004, 2005, 2007-2009, 2012-2014  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2002  Internet Software Consortium.
Danny Mayer's avatar
Danny Mayer committed
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Danny Mayer's avatar
Danny Mayer committed
6
7
8
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Mark Andrews's avatar
Mark Andrews committed
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Danny Mayer's avatar
Danny Mayer committed
16
17
 */

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: os.c,v 1.39 2012/02/06 23:46:44 tbox Exp $ */
Danny Mayer's avatar
Danny Mayer committed
19
20
21
22

#include <config.h>
#include <stdarg.h>

Evan Hunt's avatar
Evan Hunt committed
23
#include <sys/types.h>
Danny Mayer's avatar
Danny Mayer committed
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <sys/stat.h>

#include <ctype.h>
#include <errno.h>
#include <io.h>
#include <process.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>

#include <isc/print.h>
#include <isc/result.h>
37
#include <isc/strerror.h>
Danny Mayer's avatar
Danny Mayer committed
38
39
#include <isc/string.h>
#include <isc/ntpaths.h>
40
#include <isc/util.h>
41
#include <isc/win32os.h>
Danny Mayer's avatar
Danny Mayer committed
42
43

#include <named/main.h>
44
#include <named/log.h>
Danny Mayer's avatar
Danny Mayer committed
45
46
47
48
49
50
#include <named/os.h>
#include <named/globals.h>
#include <named/ntservice.h>


static char *pidfile = NULL;
51
static int devnullfd = -1;
52
static int singletonfd = -1;
Danny Mayer's avatar
Danny Mayer committed
53
54
55

static BOOL Initialized = FALSE;

Automatic Updater's avatar
Automatic Updater committed
56
static char *version_error =
57
58
	"named requires Windows 2000 Service Pack 2 or later to run correctly";

Danny Mayer's avatar
Danny Mayer committed
59
void
60
ns_paths_init(void) {
61
	if (!Initialized)
Danny Mayer's avatar
Danny Mayer committed
62
		isc_ntpaths_init();
63

Danny Mayer's avatar
Danny Mayer committed
64
65
66
67
68
69
	ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH);
	lwresd_g_conffile = isc_ntpaths_get(LWRES_CONF_PATH);
	lwresd_g_resolvconffile = isc_ntpaths_get(RESOLV_CONF_PATH);
	ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH);
	ns_g_defaultpidfile = isc_ntpaths_get(NAMED_PID_PATH);
	lwresd_g_defaultpidfile = isc_ntpaths_get(LWRESD_PID_PATH);
70
	ns_g_keyfile = isc_ntpaths_get(RNDC_KEY_PATH);
71
	ns_g_defaultsessionkeyfile = isc_ntpaths_get(SESSION_KEY_PATH);
Danny Mayer's avatar
Danny Mayer committed
72
73
74
75

	Initialized = TRUE;
}

76
77
78
79
80
81
82
83
/*
 * Due to Knowledge base article Q263823 we need to make sure that
 * Windows 2000 systems have Service Pack 2 or later installed and
 * warn when it isn't.
 */
static void
version_check(const char *progname) {

84
85
	if ((isc_win32os_versioncheck(4, 0, 0, 0) >= 0) &&
	    (isc_win32os_versioncheck(5, 0, 0, 0) < 0))
86
		return;	/* No problem with Version 4.0 */
87
	if (isc_win32os_versioncheck(5, 0, 2, 0) < 0)
88
89
		if (ntservice_isservice())
			NTReportError(progname, version_error);
Automatic Updater's avatar
Automatic Updater committed
90
		else
91
92
			fprintf(stderr, "%s\n", version_error);
}
Danny Mayer's avatar
Danny Mayer committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

static void
setup_syslog(const char *progname) {
	int options;

	options = LOG_PID;
#ifdef LOG_NDELAY
	options |= LOG_NDELAY;
#endif

	openlog(progname, options, LOG_DAEMON);
}

void
ns_os_init(const char *progname) {
	ns_paths_init();
	setup_syslog(progname);
110
111
112
113
114
115
116
117
118
119
	/*
	 * XXXMPA. We may need to split ntservice_init() in two and
	 * just mark as running in ns_os_started().  If we do that
	 * this is where the first part of ntservice_init() should be
	 * called from.
	 *
	 * XXX970 Remove comment if no problems by 9.7.0.
	 *
	 * ntservice_init();
	 */
120
	version_check(progname);
Danny Mayer's avatar
Danny Mayer committed
121
122
123
124
125
126
127
128
}

void
ns_os_daemonize(void) {
	/*
	 * Try to set stdin, stdout, and stderr to /dev/null, but press
	 * on even if it fails.
	 */
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
	if (devnullfd != -1) {
		if (devnullfd != _fileno(stdin)) {
			close(_fileno(stdin));
			(void)_dup2(devnullfd, _fileno(stdin));
		}
		if (devnullfd != _fileno(stdout)) {
			close(_fileno(stdout));
			(void)_dup2(devnullfd, _fileno(stdout));
		}
		if (devnullfd != _fileno(stderr)) {
			close(_fileno(stderr));
			(void)_dup2(devnullfd, _fileno(stderr));
		}
	}
}

void
ns_os_opendevnull(void) {
	devnullfd = open("NUL", O_RDWR, 0);
}

void
ns_os_closedevnull(void) {
	if (devnullfd != _fileno(stdin) &&
	    devnullfd != _fileno(stdout) &&
	    devnullfd != _fileno(stderr)) {
		close(devnullfd);
		devnullfd = -1;
Danny Mayer's avatar
Danny Mayer committed
157
158
159
160
161
	}
}

void
ns_os_chroot(const char *root) {
Mark Andrews's avatar
Mark Andrews committed
162
163
	if (root != NULL)
		ns_main_earlyfatal("chroot(): isn't supported by Win32 API");
Danny Mayer's avatar
Danny Mayer committed
164
165
166
167
168
169
170
171
172
173
}

void
ns_os_inituserinfo(const char *username) {
}

void
ns_os_changeuser(void) {
}

174
175
176
177
void
ns_os_adjustnofile(void) {
}

Danny Mayer's avatar
Danny Mayer committed
178
179
180
181
182
void
ns_os_minprivs(void) {
}

static int
Evan Hunt's avatar
Evan Hunt committed
183
safe_open(const char *filename, int mode, isc_boolean_t append) {
Danny Mayer's avatar
Danny Mayer committed
184
	int fd;
Mark Andrews's avatar
Mark Andrews committed
185
	struct stat sb;
Danny Mayer's avatar
Danny Mayer committed
186

Mark Andrews's avatar
Mark Andrews committed
187
188
	if (stat(filename, &sb) == -1) {
		if (errno != ENOENT)
Danny Mayer's avatar
Danny Mayer committed
189
			return (-1);
Mark Andrews's avatar
Mark Andrews committed
190
	} else if ((sb.st_mode & S_IFREG) == 0)
Danny Mayer's avatar
Danny Mayer committed
191
192
193
		return (-1);

	if (append)
194
		fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, mode);
Danny Mayer's avatar
Danny Mayer committed
195
196
	else {
		(void)unlink(filename);
197
		fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
Danny Mayer's avatar
Danny Mayer committed
198
199
200
201
202
203
204
205
206
207
208
209
210
	}
	return (fd);
}

static void
cleanup_pidfile(void) {
	if (pidfile != NULL) {
		(void)unlink(pidfile);
		free(pidfile);
	}
	pidfile = NULL;
}

211
FILE *
Evan Hunt's avatar
Evan Hunt committed
212
ns_os_openfile(const char *filename, int mode, isc_boolean_t switch_user) {
213
214
215
216
217
218
219
220
221
222
	char strbuf[ISC_STRERRORSIZE];
	FILE *fp;
	int fd;

	UNUSED(switch_user);
	fd = safe_open(filename, mode, ISC_FALSE);
	if (fd < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ns_main_earlywarning("could not open file '%s': %s",
				     filename, strbuf);
223
		return (NULL);
224
225
226
	}

	fp = fdopen(fd, "w");
Evan Hunt's avatar
Evan Hunt committed
227
	if (fp == NULL) {
228
229
230
231
232
233
234
235
236
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ns_main_earlywarning("could not fdopen() file '%s': %s",
				     filename, strbuf);
		close(fd);
	}

	return (fp);
}

Danny Mayer's avatar
Danny Mayer committed
237
void
238
ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
Danny Mayer's avatar
Danny Mayer committed
239
240
	FILE *lockfile;
	pid_t pid;
241
	char strbuf[ISC_STRERRORSIZE];
242
	void (*report)(const char *, ...);
Danny Mayer's avatar
Danny Mayer committed
243
244
245
246
247

	/*
	 * The caller must ensure any required synchronization.
	 */

248
249
	report = first_time ? ns_main_earlyfatal : ns_main_earlywarning;

Danny Mayer's avatar
Danny Mayer committed
250
251
	cleanup_pidfile();

252
	if (filename == NULL)
253
		return;
254

Evan Hunt's avatar
Evan Hunt committed
255
	pidfile = strdup(filename);
256
	if (pidfile == NULL) {
257
		isc__strerror(errno, strbuf, sizeof(strbuf));
258
		(*report)("couldn't strdup() '%s': %s", filename, strbuf);
259
		return;
260
	}
Danny Mayer's avatar
Danny Mayer committed
261

262
263
264
	lockfile = ns_os_openfile(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
				  ISC_FALSE);
	if (lockfile == NULL) {
265
266
267
		free(pidfile);
		pidfile = NULL;
		return;
268
	}
Danny Mayer's avatar
Danny Mayer committed
269

270
271
	pid = getpid();

Mark Andrews's avatar
Mark Andrews committed
272
273
	if (fprintf(lockfile, "%ld\n", (long)pid) < 0) {
		(*report)("fprintf() to pid file '%s' failed", filename);
274
		(void)fclose(lockfile);
275
276
277
		cleanup_pidfile();
		return;
	}
Mark Andrews's avatar
Mark Andrews committed
278
279
	if (fflush(lockfile) == EOF) {
		(*report)("fflush() to pid file '%s' failed", filename);
280
		(void)fclose(lockfile);
281
282
283
		cleanup_pidfile();
		return;
	}
Danny Mayer's avatar
Danny Mayer committed
284
285
286
	(void)fclose(lockfile);
}

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
isc_boolean_t
ns_os_issingleton(const char *filename) {
	OVERLAPPED o;

	if (singletonfd != -1)
		return (ISC_TRUE);

	/*
	 * ns_os_openfile() uses safeopen() which removes any existing
	 * files. We can't use that here.
	 */
	singletonfd = open(filename, O_WRONLY | O_CREAT,
			   S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	if (singletonfd == -1)
		return (ISC_FALSE);

	memset(&o, 0, sizeof(o));
	/* Expect ERROR_LOCK_VIOLATION if already locked */
	if (!LockFileEx((HANDLE) _get_osfhandle(singletonfd),
			LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
			0, 0, 1, &o)) {
		close(singletonfd);
		singletonfd = -1;
		return (ISC_FALSE);
	}

	return (ISC_TRUE);
}

Danny Mayer's avatar
Danny Mayer committed
316
317
318
319
void
ns_os_shutdown(void) {
	closelog();
	cleanup_pidfile();
320
321
322
323
324
325
326

	if (singletonfd != -1) {
		(void) UnlockFile((HANDLE) _get_osfhandle(singletonfd),
				  0, 0, 0, 1);
		close(singletonfd);
		singletonfd = -1;
	}
Danny Mayer's avatar
Danny Mayer committed
327
328
	ntservice_shutdown();	/* This MUST be the last thing done */
}
329
330
331

isc_result_t
ns_os_gethostname(char *buf, size_t len) {
Mark Andrews's avatar
Mark Andrews committed
332
	int n;
333

334
	n = gethostname(buf, (int)len);
335
	return ((n == 0) ? ISC_R_SUCCESS : ISC_R_FAILURE);
336
}
337

338
339
340
341
342
void
ns_os_shutdownmsg(char *command, isc_buffer_t *text) {
	UNUSED(command);
	UNUSED(text);
}
343
344
345
346
347
348
349

void
ns_os_tzset(void) {
#ifdef HAVE_TZSET
	tzset();
#endif
}
350
351
352

void
ns_os_started(void) {
353
	ntservice_init();
354
}