xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/mdnsd/PosixDaemon.c (revision 68c47f65208790c466e5e484f2293d3baed71c6a)
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 
17 	File:		daemon.c
18 
19 	Contains:	main & associated Application layer for mDNSResponder on Linux.
20 
21 	Change History (most recent first):
22 
23 $Log: PosixDaemon.c,v $
24 Revision 1.29.2.1  2006/08/29 06:24:34  cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26 
27 Revision 1.29  2005/08/04 03:37:45  mkrochma
28 Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed
29 
30 Revision 1.28  2005/07/19 11:21:09  cheshire
31 <rdar://problem/4170449> Unix Domain Socket leak in mdnsd
32 
33 Revision 1.27  2005/02/04 00:39:59  cheshire
34 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
35 
36 Revision 1.26  2005/02/02 02:21:30  cheshire
37 Update references to "mDNSResponder" to say "mdnsd" instead
38 
39 Revision 1.25  2005/01/27 20:01:50  cheshire
40 udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
41 
42 Revision 1.24  2005/01/19 19:20:49  ksekar
43 <rdar://problem/3960191> Need a way to turn off domain discovery
44 
45 Revision 1.23  2004/12/16 20:17:11  cheshire
46 <rdar://problem/3324626> Cache memory management improvements
47 
48 Revision 1.22  2004/12/10 13:12:08  cheshire
49 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
50 
51 Revision 1.21  2004/12/01 20:57:20  ksekar
52 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
53 
54 Revision 1.20  2004/12/01 04:28:43  cheshire
55 <rdar://problem/3872803> Darwin patches for Solaris and Suse
56 Use version of daemon() provided in mDNSUNP.c instead of local copy
57 
58 Revision 1.19  2004/12/01 03:30:29  cheshire
59 <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
60 
61 Revision 1.18  2004/11/30 22:45:59  cheshire
62 Minor code tidying
63 
64 Revision 1.17  2004/11/30 22:18:59  cheshire
65 <rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
66 
67 Revision 1.16  2004/09/21 21:05:12	cheshire
68 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
69 into mDNSShared/uds_daemon.c
70 
71 Revision 1.15  2004/09/17 01:08:53	cheshire
72 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
73   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
74   declared in that file are ONLY appropriate to single-address-space embedded applications.
75   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
76 
77 Revision 1.14  2004/09/16 00:24:49	cheshire
78 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
79 
80 Revision 1.13  2004/08/11 01:59:41	cheshire
81 Remove "mDNS *globalInstance" parameter from udsserver_init()
82 
83 Revision 1.12  2004/06/28 23:19:19	cheshire
84 Fix "Daemon_Init declared but never defined" warning on Linux
85 
86 Revision 1.11  2004/06/25 00:26:27	rpantos
87 Changes to fix the Posix build on Solaris.
88 
89 Revision 1.10  2004/06/08 04:59:40	cheshire
90 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
91 
92 Revision 1.9  2004/05/29 00:14:20  rpantos
93 <rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
94 
95 Revision 1.8  2004/04/07 01:19:04  cheshire
96 Hash slot value should be unsigned
97 
98 Revision 1.7  2004/02/14 06:34:57  cheshire
99 Use LogMsg instead of fprintf( stderr
100 
101 Revision 1.6  2004/02/14 01:10:42  rpantos
102 Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
103 
104 Revision 1.5  2004/02/05 07:45:43  cheshire
105 Add Log header
106 
107 Revision 1.4  2004/01/28 21:14:23  cheshire
108 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
109 
110 Revision 1.3  2004/01/19 19:51:46  cheshire
111 Fix compiler error (mixed declarations and code) on some versions of Linux
112 
113 Revision 1.2  2003/12/11 03:03:51  rpantos
114 Clean up mDNSPosix so that it builds on OS X again.
115 
116 Revision 1.1  2003/12/08 20:47:02  rpantos
117 Add support for mDNSResponder on Linux.
118 */
119 
120 #pragma ident	"%Z%%M%	%I%	%E% SMI"
121 
122 #include <stdio.h>
123 #include <string.h>
124 #include <unistd.h>
125 #include <stdlib.h>
126 #include <signal.h>
127 #include <errno.h>
128 #include <fcntl.h>
129 #include <pwd.h>
130 #include <sys/types.h>
131 
132 #include "mDNSEmbeddedAPI.h"
133 #include "mDNSDebug.h"
134 #include "mDNSPosix.h"
135 #include "uds_daemon.h"
136 #include "PlatformCommon.h"
137 #include "mDNSUNP.h"
138 
139 #ifndef MDNSD_USER
140 #define MDNSD_USER "nobody"
141 #endif
142 
143 #define CONFIG_FILE "/etc/mdnsd.conf"
144 static domainname DynDNSZone;                // Default wide-area zone for service registration
145 static domainname DynDNSHostname;
146 
147 #define RR_CACHE_SIZE 500
148 static CacheEntity gRRCache[RR_CACHE_SIZE];
149 
150 extern const char mDNSResponderVersionString[];
151 
152 static void Reconfigure(mDNS *m)
153 	{
154 	mDNSAddr DynDNSIP;
155 	mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
156 	mDNS_DeleteDNSServers(m);
157 	if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
158 		LogMsgNoIdent("Unable to parse DNS server list. Unicast DNS-SD unavailable");
159 	ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
160 	FindDefaultRouteIP(&DynDNSIP);
161 	if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
162 	if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
163 	}
164 
165 // Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
166 static void ParseCmdLinArgs(int argc, char **argv)
167 	{
168 	if (argc > 1)
169 		{
170 		if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
171 		else printf("Usage: %s [-debug]\n", argv[0]);
172 		}
173 
174 	if (!mDNS_DebugMode)
175 		{
176 		int result = daemon(0, 0);
177 		if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
178 #if __APPLE__
179 		LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
180 		exit(-1);
181 #endif
182 		}
183 	}
184 
185 static void		DumpStateLog(mDNS *const m)
186 // Dump a little log of what we've been up to.
187 	{
188 	LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
189 	udsserver_info(m);
190 	LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
191 	}
192 
193 static mStatus	MainLoop(mDNS *m) // Loop until we quit.
194 	{
195 	sigset_t	signals;
196 	mDNSBool	gotData = mDNSfalse;
197 
198 	mDNSPosixListenForSignalInEventLoop(SIGINT);
199 	mDNSPosixListenForSignalInEventLoop(SIGTERM);
200 	mDNSPosixListenForSignalInEventLoop(SIGUSR1);
201 	mDNSPosixListenForSignalInEventLoop(SIGPIPE);
202 	mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
203 
204 	for (; ;)
205 		{
206 		// Work out how long we expect to sleep before the next scheduled task
207 		struct timeval	timeout;
208 		mDNSs32			ticks;
209 
210 		// Only idle if we didn't find any data the last time around
211 		if (!gotData)
212 			{
213 			mDNSs32			nextTimerEvent = mDNS_Execute(m);
214 			nextTimerEvent = udsserver_idle(nextTimerEvent);
215 			ticks = nextTimerEvent - mDNS_TimeNow(m);
216 			if (ticks < 1) ticks = 1;
217 			}
218 		else	// otherwise call EventLoop again with 0 timemout
219 			ticks = 0;
220 
221 		timeout.tv_sec = ticks / mDNSPlatformOneSecond;
222 		timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
223 
224 		(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
225 
226 		if (sigismember(&signals, SIGHUP )) Reconfigure(m);
227 		if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
228 		// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
229 		if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
230 		if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
231 		}
232 	return EINTR;
233 	}
234 
235 int		main(int argc, char **argv)
236 	{
237 	#define mDNSRecord mDNSStorage
238 	mDNS_PlatformSupport	platformStorage;
239 	mStatus					err;
240 
241 	bzero(&mDNSRecord, sizeof mDNSRecord);
242 	bzero(&platformStorage, sizeof platformStorage);
243 
244 	ParseCmdLinArgs(argc, argv);
245 
246 	LogMsgIdent(mDNSResponderVersionString, "starting");
247 
248 	err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
249 					mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
250 
251 	if (mStatus_NoError == err)
252 		err = udsserver_init();
253 
254 	Reconfigure(&mDNSRecord);
255 
256 	// Now that we're finished with anything privileged, switch over to running as "nobody"
257 	if (mStatus_NoError == err)
258 		{
259 		const struct passwd *pw = getpwnam(MDNSD_USER);
260 		if (pw != NULL)
261 			setuid(pw->pw_uid);
262 		else
263 #ifdef MDNSD_NOROOT
264 		     {
265 			LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
266 			err = mStatus_Invalid;
267 		     }
268 #else
269 			LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
270 #endif
271 		}
272 
273 	if (mStatus_NoError == err)
274 		err = MainLoop(&mDNSRecord);
275 
276 	LogMsgIdent(mDNSResponderVersionString, "stopping");
277 
278 	mDNS_Close(&mDNSRecord);
279 
280 	if (udsserver_exit() < 0)
281 		LogMsg("ExitCallback: udsserver_exit failed");
282 
283  #if MDNS_DEBUGMSGS > 0
284 	printf("mDNSResponder exiting normally with %ld\n", err);
285  #endif
286 
287 	return err;
288 	}
289 
290 //		uds_daemon support		////////////////////////////////////////////////////////////
291 
292 #undef LogMalloc
293 
294 #if MDNS_MALLOC_DEBUGGING >= 2
295 #define LogMalloc LogMsg
296 #else
297 #define LogMalloc(ARGS...) ((void)0)
298 #endif
299 
300 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
301 /* Support routine for uds_daemon.c */
302 	{
303 	// Depends on the fact that udsEventCallback == mDNSPosixEventCallback
304 	return mDNSPosixAddFDToEventLoop(fd, callback, context);
305 	}
306 
307 mStatus udsSupportRemoveFDFromEventLoop(int fd)		// Note: This also CLOSES the file descriptor
308 	{
309 	mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
310 	close(fd);
311 	return err;
312 	}
313 
314 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
315 	{
316 	(void)m;
317 	(void)delay;
318 	// No-op, for now
319 	}
320 
321 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
322 
323 void *mallocL(char *msg, unsigned int size)
324 	{
325 	unsigned long *mem = malloc(size+8);
326 	if (!mem)
327 		{
328 		LogMsg("malloc( %s : %d ) failed", msg, size);
329 		return(NULL);
330 		}
331 	else
332 		{
333 		LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
334 		mem[0] = 0xDEAD1234;
335 		mem[1] = size;
336 		//bzero(&mem[2], size);
337 		memset(&mem[2], 0xFF, size);
338 //		validatelists(&mDNSStorage);
339 		return(&mem[2]);
340 		}
341 	}
342 
343 void freeL(char *msg, void *x)
344 	{
345 	if (!x)
346 		LogMsg("free( %s @ NULL )!", msg);
347 	else
348 		{
349 		unsigned long *mem = ((unsigned long *)x) - 2;
350 		if (mem[0] != 0xDEAD1234)
351 			{ LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
352 		if (mem[1] > 8000)
353 			{ LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
354 		LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
355 		//bzero(mem, mem[1]+8);
356 		memset(mem, 0xDD, mem[1]+8);
357 //		validatelists(&mDNSStorage);
358 		free(mem);
359 		}
360 	}
361 
362 #endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
363 
364 // For convenience when using the "strings" command, this is the last thing in the file
365 #if mDNSResponderVersion > 1
366 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
367 #elif MDNS_VERSIONSTR_NODTS
368 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) ";
369 #else
370 mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
371 #endif
372