• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 #include	<stdio.h>
19 #include	<stdlib.h>
20 #include	<crtdbg.h>
21 #include	<stdarg.h>
22 #include	<stddef.h>
23 
24 
25 #include	"CommonServices.h"
26 #include	"DebugServices.h"
27 #include	"RegNames.h"
28 
29 #include	"uds_daemon.h"
30 #include	"GenLinkedList.h"
31 #include	"Service.h"
32 #include	"EventLog.h"
33 
34 #include	"Resource.h"
35 
36 #include	"mDNSEmbeddedAPI.h"
37 #include	"uDNS.h"
38 #include	"mDNSWin32.h"
39 
40 #include	"Firewall.h"
41 
42 #if( !TARGET_OS_WINDOWS_CE )
43 	#include	<mswsock.h>
44 	#include	<process.h>
45 	#include	<ipExport.h>
46 	#include	<ws2def.h>
47 	#include	<ws2ipdef.h>
48 	#include	<iphlpapi.h>
49 	#include	<netioapi.h>
50 	#include	<iptypes.h>
51 	#include	<powrprof.h>
52 #endif
53 
54 #ifndef HeapEnableTerminationOnCorruption
55 #	define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
56 #endif
57 
58 #if 0
59 #pragma mark == Constants ==
60 #endif
61 
62 //===========================================================================================================================
63 //	Constants
64 //===========================================================================================================================
65 
66 #define	DEBUG_NAME							"[mDNSWin32] "
67 #define kServiceFirewallName				L"Bonjour"
68 #define	kServiceDependencies				TEXT("Tcpip\0\0")
69 #define	kDNSServiceCacheEntryCountDefault	512
70 #define kRetryFirewallPeriod				30 * 1000
71 #define kDefValueSize						MAX_PATH + 1
72 #define kZeroIndex							0
73 #define kDefaultRouteMetric					399
74 #define kSecondsTo100NSUnits				( 10 * 1000 * 1000 )
75 #define kSPSMaintenanceWakePeriod			-30
76 
77 #define RR_CACHE_SIZE 500
78 static CacheEntity gRRCache[RR_CACHE_SIZE];
79 #if 0
80 #pragma mark == Structures ==
81 #endif
82 
83 //===========================================================================================================================
84 //	Structures
85 //===========================================================================================================================
86 
87 typedef struct EventSource
88 {
89 	HANDLE							event;
90 	void						*	context;
91 	RegisterWaitableEventHandler	handler;
92 	struct EventSource			*	next;
93 } EventSource;
94 
95 static BOOL											gEventSourceListChanged = FALSE;
96 static EventSource								*	gEventSourceList = NULL;
97 static EventSource								*	gCurrentSource = NULL;
98 static int											gEventSources = 0;
99 
100 #define	kWaitListStopEvent							( WAIT_OBJECT_0 + 0 )
101 #define	kWaitListInterfaceListChangedEvent			( WAIT_OBJECT_0 + 1 )
102 #define kWaitListComputerDescriptionEvent			( WAIT_OBJECT_0 + 2 )
103 #define kWaitListTCPIPEvent							( WAIT_OBJECT_0 + 3 )
104 #define kWaitListDynDNSEvent						( WAIT_OBJECT_0 + 4 )
105 #define kWaitListFileShareEvent						( WAIT_OBJECT_0 + 5 )
106 #define kWaitListFirewallEvent						( WAIT_OBJECT_0 + 6 )
107 #define kWaitListAdvertisedServicesEvent			( WAIT_OBJECT_0 + 7 )
108 #define kWaitListSPSWakeupEvent						( WAIT_OBJECT_0 + 8 )
109 #define kWaitListSPSSleepEvent						( WAIT_OBJECT_0 + 9 )
110 #define	kWaitListFixedItemCount						10
111 
112 
113 #if 0
114 #pragma mark == Prototypes ==
115 #endif
116 
117 //===========================================================================================================================
118 //	Prototypes
119 //===========================================================================================================================
120 static void			Usage( void );
121 static BOOL WINAPI	ConsoleControlHandler( DWORD inControlEvent );
122 static OSStatus		InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
123 static OSStatus		RemoveService( LPCTSTR inName );
124 static OSStatus		SetServiceParameters();
125 static OSStatus		GetServiceParameters();
126 static OSStatus		CheckFirewall();
127 static OSStatus		SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
128 static void			ReportStatus( int inType, const char *inFormat, ... );
129 
130 static void WINAPI	ServiceMain( DWORD argc, LPTSTR argv[] );
131 static OSStatus		ServiceSetupEventLogging( void );
132 static DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
133 
134 static OSStatus		ServiceRun( int argc, LPTSTR argv[] );
135 static void			ServiceStop( void );
136 
137 static OSStatus		ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
138 static OSStatus		ServiceSpecificRun( int argc, LPTSTR argv[] );
139 static OSStatus		ServiceSpecificStop( void );
140 static void			ServiceSpecificFinalize( int argc, LPTSTR argv[] );
141 static mStatus		SetupNotifications();
142 static mStatus		TearDownNotifications();
143 static mStatus		RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
144 static void			UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event );
145 static mStatus		SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
146 static void			UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context );
147 static void			UDSCanRead( TCPSocket * sock );
148 static void			HandlePowerSuspend( void * v );
149 static void			HandlePowerResumeSuspend( void * v );
150 static void			CoreCallback(mDNS * const inMDNS, mStatus result);
151 static mDNSu8		SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
152 static OSStatus		GetRouteDestination(DWORD * ifIndex, DWORD * address);
153 static OSStatus		SetLLRoute( mDNS * const inMDNS );
154 static bool			HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
155 static bool			IsValidAddress( const char * addr );
156 static bool			IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
157 static bool			IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
158 static bool			IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
159 static const char * strnistr( const char * string, const char * subString, size_t max );
160 
161 #if defined(UNICODE)
162 #	define StrLen(X)	wcslen(X)
163 #	define StrCmp(X,Y)	wcscmp(X,Y)
164 #else
165 #	define StrLen(X)	strlen(X)
166 #	define StrCmp(X,Y)	strcmp(X,Y)
167 #endif
168 
169 
170 #define kLLNetworkAddr      "169.254.0.0"
171 #define kLLNetworkAddrMask  "255.255.0.0"
172 
173 
174 #include	"mDNSEmbeddedAPI.h"
175 
176 #if 0
177 #pragma mark == Globals ==
178 #endif
179 
180 //===========================================================================================================================
181 //	Globals
182 //===========================================================================================================================
183 #define gMDNSRecord mDNSStorage
184 DEBUG_LOCAL	mDNS_PlatformSupport		gPlatformStorage;
185 DEBUG_LOCAL BOOL						gServiceQuietMode		= FALSE;
186 DEBUG_LOCAL SERVICE_TABLE_ENTRY			gServiceDispatchTable[] =
187 {
188 	{ kServiceName,	ServiceMain },
189 	{ NULL, 		NULL }
190 };
191 DEBUG_LOCAL SOCKET						gInterfaceListChangedSocket	= INVALID_SOCKET;
192 DEBUG_LOCAL HANDLE						gInterfaceListChangedEvent	= NULL;
193 DEBUG_LOCAL HKEY						gDescKey					= NULL;
194 DEBUG_LOCAL HANDLE						gDescChangedEvent			= NULL;	// Computer description changed event
195 DEBUG_LOCAL HKEY						gTcpipKey					= NULL;
196 DEBUG_LOCAL HANDLE						gTcpipChangedEvent			= NULL;	// TCP/IP config changed
197 DEBUG_LOCAL HKEY						gDdnsKey					= NULL;
198 DEBUG_LOCAL HANDLE						gDdnsChangedEvent			= NULL;	// DynDNS config changed
199 DEBUG_LOCAL HKEY						gFileSharingKey				= NULL;
200 DEBUG_LOCAL HANDLE						gFileSharingChangedEvent	= NULL;	// File Sharing changed
201 DEBUG_LOCAL HKEY						gFirewallKey				= NULL;
202 DEBUG_LOCAL HANDLE						gFirewallChangedEvent		= NULL;	// Firewall changed
203 DEBUG_LOCAL HKEY						gAdvertisedServicesKey		= NULL;
204 DEBUG_LOCAL HANDLE						gAdvertisedServicesChangedEvent	= NULL; // Advertised services changed
205 DEBUG_LOCAL SERVICE_STATUS				gServiceStatus;
206 DEBUG_LOCAL SERVICE_STATUS_HANDLE		gServiceStatusHandle 	= NULL;
207 DEBUG_LOCAL HANDLE						gServiceEventSource		= NULL;
208 DEBUG_LOCAL bool						gServiceAllowRemote		= false;
209 DEBUG_LOCAL int							gServiceCacheEntryCount	= 0;	// 0 means to use the DNS-SD default.
210 DEBUG_LOCAL bool						gServiceManageLLRouting = true;
211 DEBUG_LOCAL int							gWaitCount				= 0;
212 DEBUG_LOCAL HANDLE					*	gWaitList				= NULL;
213 DEBUG_LOCAL HANDLE						gStopEvent				= NULL;
214 DEBUG_LOCAL HANDLE						gSPSWakeupEvent			= NULL;
215 DEBUG_LOCAL HANDLE						gSPSSleepEvent			= NULL;
216 DEBUG_LOCAL HANDLE						gUDSEvent				= NULL;
217 DEBUG_LOCAL SocketRef					gUDSSocket				= 0;
218 DEBUG_LOCAL udsEventCallback			gUDSCallback			= NULL;
219 DEBUG_LOCAL BOOL						gRetryFirewall			= FALSE;
220 DEBUG_LOCAL DWORD						gOSMajorVersion;
221 DEBUG_LOCAL DWORD						gOSMinorVersion;
222 
223 typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
224 mDNSlocal HMODULE								gIPHelperLibraryInstance		= NULL;
225 mDNSlocal GetIpInterfaceEntryFunctionPtr		gGetIpInterfaceEntryFunctionPtr	= NULL;
226 
227 
228 #if 0
229 #pragma mark -
230 #endif
231 
232 //===========================================================================================================================
233 //	Main
234 //===========================================================================================================================
Main(int argc,LPTSTR argv[])235 int	Main( int argc, LPTSTR argv[] )
236 {
237 	OSStatus		err;
238 	BOOL			ok;
239 	BOOL			start;
240 	int				i;
241 
242 	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
243 
244 	debug_initialize( kDebugOutputTypeMetaConsole );
245 	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
246 
247 	// Default to automatically starting the service dispatcher if no extra arguments are specified.
248 
249 	start = ( argc <= 1 );
250 
251 	// Parse arguments.
252 
253 	for( i = 1; i < argc; ++i )
254 	{
255 		if( StrCmp( argv[ i ], TEXT("-install") ) == 0 )			// Install
256 		{
257 			TCHAR desc[ 256 ];
258 
259 			desc[ 0 ] = 0;
260 			LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
261 			err = InstallService( kServiceName, kServiceName, desc, argv[0] );
262 			if( err )
263 			{
264 				ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
265 				goto exit;
266 			}
267 		}
268 		else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 )		// Remove
269 		{
270 			err = RemoveService( kServiceName );
271 			if( err )
272 			{
273 				ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
274 				goto exit;
275 			}
276 		}
277 		else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 )		// Start
278 		{
279 			start = TRUE;
280 		}
281 		else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 )		// Server
282 		{
283 			err = RunDirect( argc, argv );
284 			if( err )
285 			{
286 				ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
287 			}
288 			goto exit;
289 		}
290 		else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 )			// Quiet Mode (toggle)
291 		{
292 			gServiceQuietMode = !gServiceQuietMode;
293 		}
294 		else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) || 	// Help
295 				 ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
296 		{
297 			Usage();
298 			err = 0;
299 			break;
300 		}
301 		else
302 		{
303 			Usage();
304 			err = kParamErr;
305 			break;
306 		}
307 	}
308 
309 	// Start the service dispatcher if requested. This does not return until all services have terminated. If any
310 	// global initialization is needed, it should be done before starting the service dispatcher, but only if it
311 	// will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
312 
313 	if( start )
314 	{
315 		ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
316 		err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
317 		if( err != kNoErr )
318 		{
319 			ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
320 			goto exit;
321 		}
322 	}
323 	err = 0;
324 
325 exit:
326 	dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
327 	_CrtDumpMemoryLeaks();
328 	return( (int) err );
329 }
330 
331 //===========================================================================================================================
332 //	Usage
333 //===========================================================================================================================
334 
Usage(void)335 static void	Usage( void )
336 {
337 	fprintf( stderr, "\n" );
338 	fprintf( stderr, "mDNSResponder 1.0d1\n" );
339 	fprintf( stderr, "\n" );
340 	fprintf( stderr, "    <no args>    Runs the service normally\n" );
341 	fprintf( stderr, "    -install     Creates the service and starts it\n" );
342 	fprintf( stderr, "    -remove      Stops the service and deletes it\n" );
343 	fprintf( stderr, "    -start       Starts the service dispatcher after processing all other arguments\n" );
344 	fprintf( stderr, "    -server      Runs the service directly as a server (for debugging)\n" );
345 	fprintf( stderr, "    -q           Toggles Quiet Mode (no events or output)\n" );
346 	fprintf( stderr, "    -remote      Allow remote connections\n" );
347 	fprintf( stderr, "    -cache n     Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
348 	fprintf( stderr, "    -h[elp]      Display Help/Usage\n" );
349 	fprintf( stderr, "\n" );
350 }
351 
352 //===========================================================================================================================
353 //	ConsoleControlHandler
354 //===========================================================================================================================
355 
ConsoleControlHandler(DWORD inControlEvent)356 static BOOL WINAPI	ConsoleControlHandler( DWORD inControlEvent )
357 {
358 	BOOL			handled;
359 	OSStatus		err;
360 
361 	handled = FALSE;
362 	switch( inControlEvent )
363 	{
364 		case CTRL_C_EVENT:
365 		case CTRL_BREAK_EVENT:
366 		case CTRL_CLOSE_EVENT:
367 		case CTRL_LOGOFF_EVENT:
368 		case CTRL_SHUTDOWN_EVENT:
369 			err = ServiceSpecificStop();
370 			require_noerr( err, exit );
371 
372 			handled = TRUE;
373 			break;
374 
375 		default:
376 			break;
377 	}
378 
379 exit:
380 	return( handled );
381 }
382 
383 //===========================================================================================================================
384 //	InstallService
385 //===========================================================================================================================
386 
InstallService(LPCTSTR inName,LPCTSTR inDisplayName,LPCTSTR inDescription,LPCTSTR inPath)387 static OSStatus	InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
388 {
389 	OSStatus		err;
390 	SC_HANDLE		scm;
391 	SC_HANDLE		service;
392 	BOOL			ok;
393 	TCHAR			fullPath[ MAX_PATH ];
394 	TCHAR *			namePtr;
395 	DWORD			size;
396 
397 	scm		= NULL;
398 	service = NULL;
399 
400 	// Get a full path to the executable since a relative path may have been specified.
401 
402 	size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
403 	err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
404 	require_noerr( err, exit );
405 
406 	// Create the service and start it.
407 
408 	scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
409 	err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
410 	require_noerr( err, exit );
411 
412 	service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
413 							 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies,
414 							 NULL, NULL );
415 	err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
416 	require_noerr( err, exit );
417 
418 	err = SetServiceParameters();
419 	check_noerr( err );
420 
421 	if( inDescription )
422 	{
423 		err = SetServiceInfo( scm, inName, inDescription );
424 		check_noerr( err );
425 	}
426 
427 	ok = StartService( service, 0, NULL );
428 	err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
429 	require_noerr( err, exit );
430 
431 	ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
432 	err = kNoErr;
433 
434 exit:
435 	if( service )
436 	{
437 		CloseServiceHandle( service );
438 	}
439 	if( scm )
440 	{
441 		CloseServiceHandle( scm );
442 	}
443 	return( err );
444 }
445 
446 //===========================================================================================================================
447 //	RemoveService
448 //===========================================================================================================================
449 
RemoveService(LPCTSTR inName)450 static OSStatus	RemoveService( LPCTSTR inName )
451 {
452 	OSStatus			err;
453 	SC_HANDLE			scm;
454 	SC_HANDLE			service;
455 	BOOL				ok;
456 	SERVICE_STATUS		status;
457 
458 	scm		= NULL;
459 	service = NULL;
460 
461 	// Open a connection to the service.
462 
463 	scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
464 	err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
465 	require_noerr( err, exit );
466 
467 	service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
468 	err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
469 	require_noerr( err, exit );
470 
471 	// Stop the service, if it is not already stopped, then delete it.
472 
473 	ok = QueryServiceStatus( service, &status );
474 	err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
475 	require_noerr( err, exit );
476 
477 	if( status.dwCurrentState != SERVICE_STOPPED )
478 	{
479 		ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
480 		check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
481 	}
482 
483 	ok = DeleteService( service );
484 	err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
485 	require_noerr( err, exit );
486 
487 	ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
488 	err = ERROR_SUCCESS;
489 
490 exit:
491 	if( service )
492 	{
493 		CloseServiceHandle( service );
494 	}
495 	if( scm )
496 	{
497 		CloseServiceHandle( scm );
498 	}
499 	return( err );
500 }
501 
502 
503 
504 //===========================================================================================================================
505 //	SetServiceParameters
506 //===========================================================================================================================
507 
SetServiceParameters()508 static OSStatus SetServiceParameters()
509 {
510 	DWORD 			value;
511 	DWORD			valueLen = sizeof(DWORD);
512 	DWORD			type;
513 	OSStatus		err;
514 	HKEY			key;
515 
516 	key = NULL;
517 
518 	//
519 	// Add/Open Parameters section under service entry in registry
520 	//
521 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
522 	require_noerr( err, exit );
523 
524 	//
525 	// If the value isn't already there, then we create it
526 	//
527 	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
528 
529 	if (err != ERROR_SUCCESS)
530 	{
531 		value = 1;
532 
533 		err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
534 		require_noerr( err, exit );
535 	}
536 
537 exit:
538 
539 	if ( key )
540 	{
541 		RegCloseKey( key );
542 	}
543 
544 	return( err );
545 }
546 
547 
548 
549 //===========================================================================================================================
550 //	GetServiceParameters
551 //===========================================================================================================================
552 
GetServiceParameters()553 static OSStatus GetServiceParameters()
554 {
555 	DWORD 			value;
556 	DWORD			valueLen;
557 	DWORD			type;
558 	OSStatus		err;
559 	HKEY			key;
560 
561 	key = NULL;
562 
563 	//
564 	// Add/Open Parameters section under service entry in registry
565 	//
566 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
567 	require_noerr( err, exit );
568 
569 	valueLen = sizeof(DWORD);
570 	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
571 	if (err == ERROR_SUCCESS)
572 	{
573 		gServiceManageLLRouting = (value) ? true : false;
574 	}
575 
576 	valueLen = sizeof(DWORD);
577 	err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
578 	if (err == ERROR_SUCCESS)
579 	{
580 		gServiceCacheEntryCount = value;
581 	}
582 
583 exit:
584 
585 	if ( key )
586 	{
587 		RegCloseKey( key );
588 	}
589 
590 	return( err );
591 }
592 
593 
594 //===========================================================================================================================
595 //	CheckFirewall
596 //===========================================================================================================================
597 
CheckFirewall()598 static OSStatus CheckFirewall()
599 {
600 	DWORD 					value;
601 	DWORD					valueLen;
602 	DWORD					type;
603 	ENUM_SERVICE_STATUS	*	lpService = NULL;
604 	SC_HANDLE				sc = NULL;
605 	HKEY					key = NULL;
606 	BOOL					ok;
607 	DWORD					bytesNeeded = 0;
608 	DWORD					srvCount;
609 	DWORD					resumeHandle = 0;
610 	DWORD					srvType;
611 	DWORD					srvState;
612 	DWORD					dwBytes = 0;
613 	DWORD					i;
614 	BOOL					isRunning = FALSE;
615 	OSStatus				err = kUnknownErr;
616 
617 	// Check to see if the firewall service is running.  If it isn't, then
618 	// we want to return immediately
619 
620 	sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
621 	err = translate_errno( sc, GetLastError(), kUnknownErr );
622 	require_noerr( err, exit );
623 
624 	srvType		=	SERVICE_WIN32;
625 	srvState	=	SERVICE_STATE_ALL;
626 
627 	for ( ;; )
628 	{
629 		// Call EnumServicesStatus using the handle returned by OpenSCManager
630 
631 		ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
632 
633 		if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
634 		{
635 			break;
636 		}
637 
638 		if ( lpService )
639 		{
640 			free( lpService );
641 		}
642 
643 		dwBytes = bytesNeeded;
644 
645 		lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
646 		require_action( lpService, exit, err = mStatus_NoMemoryErr );
647 	}
648 
649 	err = translate_errno( ok, GetLastError(), kUnknownErr );
650 	require_noerr( err, exit );
651 
652 	for ( i = 0; i < srvCount; i++ )
653 	{
654 		if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
655 		{
656 			if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
657 			{
658 				isRunning = TRUE;
659 			}
660 
661 			break;
662 		}
663 	}
664 
665 	require_action( isRunning, exit, err = kUnknownErr );
666 
667 	// Check to see if we've managed the firewall.
668 	// This package might have been installed, then
669 	// the OS was upgraded to SP2 or above.  If that's
670 	// the case, then we need to manipulate the firewall
671 	// so networking works correctly.
672 
673 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
674 	require_noerr( err, exit );
675 
676 	valueLen = sizeof(DWORD);
677 	err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
678 
679 	if ((err != ERROR_SUCCESS) || (value == 0))
680 	{
681 		wchar_t	fullPath[ MAX_PATH ];
682 		DWORD	size;
683 
684 		// Get a full path to the executable
685 
686 		size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
687 		err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
688 		require_noerr( err, exit );
689 
690 		err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
691 		require_noerr( err, exit );
692 
693 		value = 1;
694 		err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
695 		require_noerr( err, exit );
696 	}
697 
698 exit:
699 
700 	if ( key )
701 	{
702 		RegCloseKey( key );
703 	}
704 
705 	if ( lpService )
706 	{
707 		free( lpService );
708 	}
709 
710 	if ( sc )
711 	{
712 		CloseServiceHandle ( sc );
713 	}
714 
715 	return( err );
716 }
717 
718 
719 
720 //===========================================================================================================================
721 //	SetServiceInfo
722 //===========================================================================================================================
723 
SetServiceInfo(SC_HANDLE inSCM,LPCTSTR inServiceName,LPCTSTR inDescription)724 static OSStatus	SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
725 {
726 	OSStatus				err;
727 	SC_LOCK					lock;
728 	SC_HANDLE				service;
729 	SERVICE_DESCRIPTION		description;
730 	SERVICE_FAILURE_ACTIONS	actions;
731 	SC_ACTION				action;
732 	BOOL					ok;
733 
734 	check( inServiceName );
735 	check( inDescription );
736 
737 	lock 	= NULL;
738 	service	= NULL;
739 
740 	// Open the database (if not provided) and lock it to prevent other access while re-configuring.
741 
742 	if( !inSCM )
743 	{
744 		inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
745 		err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
746 		require_noerr( err, exit );
747 	}
748 
749 	lock = LockServiceDatabase( inSCM );
750 	err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
751 	require_noerr( err, exit );
752 
753 	// Open a handle to the service.
754 
755 	service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
756 	err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
757 	require_noerr( err, exit );
758 
759 	// Change the description.
760 
761 	description.lpDescription = (LPTSTR) inDescription;
762 	ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
763 	err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
764 	require_noerr( err, exit );
765 
766 	actions.dwResetPeriod	=	INFINITE;
767 	actions.lpRebootMsg		=	NULL;
768 	actions.lpCommand		=	NULL;
769 	actions.cActions		=	1;
770 	actions.lpsaActions		=	&action;
771 	action.Delay			=	500;
772 	action.Type				=	SC_ACTION_RESTART;
773 
774 	ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
775 	err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
776 	require_noerr( err, exit );
777 
778 	err = ERROR_SUCCESS;
779 
780 exit:
781 	// Close the service and release the lock.
782 
783 	if( service )
784 	{
785 		CloseServiceHandle( service );
786 	}
787 	if( lock )
788 	{
789 		UnlockServiceDatabase( lock );
790 	}
791 	return( err );
792 }
793 
794 //===========================================================================================================================
795 //	ReportStatus
796 //===========================================================================================================================
797 
ReportStatus(int inType,const char * inFormat,...)798 static void	ReportStatus( int inType, const char *inFormat, ... )
799 {
800 	if( !gServiceQuietMode )
801 	{
802 		va_list		args;
803 
804 		va_start( args, inFormat );
805 		if( gServiceEventSource )
806 		{
807 			char				s[ 1024 ];
808 			BOOL				ok;
809 			const char *		array[ 1 ];
810 
811 			vsprintf( s, inFormat, args );
812 			array[ 0 ] = s;
813 			ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
814 			check_translated_errno( ok, GetLastError(), kUnknownErr );
815 		}
816 		else
817 		{
818 			int		n;
819 
820 			n = vfprintf( stderr, inFormat, args );
821 			check( n >= 0 );
822 		}
823 		va_end( args );
824 	}
825 }
826 
827 //===========================================================================================================================
828 //	RunDirect
829 //===========================================================================================================================
830 
RunDirect(int argc,LPTSTR argv[])831 int	RunDirect( int argc, LPTSTR argv[] )
832 {
833 	OSStatus		err;
834 	BOOL			initialized;
835    BOOL        ok;
836 
837 	initialized = FALSE;
838 
839 	// Install a Console Control Handler to handle things like control-c signals.
840 
841 	ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
842 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
843 	require_noerr( err, exit );
844 
845 	err = ServiceSpecificInitialize( argc, argv );
846 	require_noerr( err, exit );
847 	initialized = TRUE;
848 
849 	// Run the service. This does not return until the service quits or is stopped.
850 
851 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
852 
853 	err = ServiceSpecificRun( argc, argv );
854 	require_noerr( err, exit );
855 
856 	// Clean up.
857 
858 exit:
859 	if( initialized )
860 	{
861 		ServiceSpecificFinalize( argc, argv );
862 	}
863 	return( err );
864 }
865 
866 #if 0
867 #pragma mark -
868 #endif
869 
870 //===========================================================================================================================
871 //	ServiceMain
872 //===========================================================================================================================
873 
ServiceMain(DWORD argc,LPTSTR argv[])874 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
875 {
876 	OSStatus		err;
877 	BOOL			ok;
878 
879 	err = ServiceSetupEventLogging();
880 	check_noerr( err );
881 
882 	err = GetServiceParameters();
883 	check_noerr( err );
884 
885 	// Initialize the service status and register the service control handler with the name of the service.
886 
887 	gServiceStatus.dwServiceType 				= SERVICE_WIN32_SHARE_PROCESS;
888 	gServiceStatus.dwCurrentState 				= 0;
889 	gServiceStatus.dwControlsAccepted 			= SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_POWEREVENT;
890 	gServiceStatus.dwWin32ExitCode 				= NO_ERROR;
891 	gServiceStatus.dwServiceSpecificExitCode 	= NO_ERROR;
892 	gServiceStatus.dwCheckPoint 				= 0;
893 	gServiceStatus.dwWaitHint 					= 0;
894 
895 	gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
896 	err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
897 	require_noerr( err, exit );
898 
899 	// Mark the service as starting.
900 
901 	gServiceStatus.dwCurrentState 	= SERVICE_START_PENDING;
902 	gServiceStatus.dwCheckPoint	 	= 0;
903 	gServiceStatus.dwWaitHint 		= 5000;	// 5 seconds
904 	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
905 	check_translated_errno( ok, GetLastError(), kParamErr );
906 
907 	// Run the service. This does not return until the service quits or is stopped.
908 
909 	err = ServiceRun( (int) argc, argv );
910 	if( err != kNoErr )
911 	{
912 		gServiceStatus.dwWin32ExitCode				= ERROR_SERVICE_SPECIFIC_ERROR;
913 		gServiceStatus.dwServiceSpecificExitCode 	= (DWORD) err;
914 	}
915 
916 	// Service-specific work is done so mark the service as stopped.
917 
918 	gServiceStatus.dwCurrentState = SERVICE_STOPPED;
919 	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
920 	check_translated_errno( ok, GetLastError(), kParamErr );
921 
922 	// Note: The service status handle should not be closed according to Microsoft documentation.
923 
924 exit:
925 	if( gServiceEventSource )
926 	{
927 		ok = DeregisterEventSource( gServiceEventSource );
928 		check_translated_errno( ok, GetLastError(), kUnknownErr );
929 		gServiceEventSource = NULL;
930 	}
931 }
932 
933 //===========================================================================================================================
934 //	ServiceSetupEventLogging
935 //===========================================================================================================================
936 
ServiceSetupEventLogging(void)937 static OSStatus	ServiceSetupEventLogging( void )
938 {
939 	OSStatus			err;
940 	HKEY				key;
941 	LPCTSTR				s;
942 	DWORD				typesSupported;
943 	TCHAR				path[ MAX_PATH ];
944 	DWORD 				n;
945 
946 	key = NULL;
947 
948 	// Add/Open source name as a sub-key under the Application key in the EventLog registry key.
949 
950 	s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
951 	err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
952 	require_noerr( err, exit );
953 
954 	// Add the name to the EventMessageFile subkey.
955 
956 	path[ 0 ] = '\0';
957 	GetModuleFileName( NULL, path, MAX_PATH );
958 	n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
959 	err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
960 	require_noerr( err, exit );
961 
962 	// Set the supported event types in the TypesSupported subkey.
963 
964 	typesSupported = 0
965 					 | EVENTLOG_SUCCESS
966 					 | EVENTLOG_ERROR_TYPE
967 					 | EVENTLOG_WARNING_TYPE
968 					 | EVENTLOG_INFORMATION_TYPE
969 					 | EVENTLOG_AUDIT_SUCCESS
970 					 | EVENTLOG_AUDIT_FAILURE;
971 	err = RegSetValueEx( key, TEXT("TypesSupported"), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
972 	require_noerr( err, exit );
973 
974 	// Set up the event source.
975 
976 	gServiceEventSource = RegisterEventSource( NULL, kServiceName );
977 	err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
978 	require_noerr( err, exit );
979 
980 exit:
981 	if( key )
982 	{
983 		RegCloseKey( key );
984 	}
985 	return( err );
986 }
987 
988 //===========================================================================================================================
989 //	HandlePowerSuspend
990 //===========================================================================================================================
991 
HandlePowerSuspend(void * v)992 static void HandlePowerSuspend( void * v )
993 {
994 	LARGE_INTEGER	timeout;
995 	BOOL			ok;
996 
997 	( void ) v;
998 
999 	dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerSuspend\n" );
1000 
1001 	gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
1002 
1003 	if ( gMDNSRecord.SystemWakeOnLANEnabled )
1004 	{
1005 		ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
1006 		check( ok );
1007 	}
1008 
1009 	mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
1010 }
1011 
1012 
1013 //===========================================================================================================================
1014 //	HandlePowerResumeSuspend
1015 //===========================================================================================================================
1016 
HandlePowerResumeSuspend(void * v)1017 static void HandlePowerResumeSuspend( void * v )
1018 {
1019 	( void ) v;
1020 
1021 	dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerResumeSuspend\n" );
1022 
1023 	if ( gSPSWakeupEvent )
1024 	{
1025 		CancelWaitableTimer( gSPSWakeupEvent );
1026 	}
1027 
1028 	if ( gSPSSleepEvent )
1029 	{
1030 		CancelWaitableTimer( gSPSSleepEvent );
1031 	}
1032 
1033 	mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
1034 }
1035 
1036 
1037 //===========================================================================================================================
1038 //	ServiceControlHandler
1039 //===========================================================================================================================
1040 
ServiceControlHandler(DWORD inControl,DWORD inEventType,LPVOID inEventData,LPVOID inContext)1041 static DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
1042 {
1043 	BOOL		setStatus;
1044 	BOOL		ok;
1045 
1046 	DEBUG_UNUSED( inEventData );
1047 	DEBUG_UNUSED( inContext );
1048 
1049 	setStatus = TRUE;
1050 	switch( inControl )
1051 	{
1052 		case SERVICE_CONTROL_STOP:
1053 		case SERVICE_CONTROL_SHUTDOWN:
1054 			dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
1055 
1056 			ServiceStop();
1057 			setStatus = FALSE;
1058 			break;
1059 
1060 		case SERVICE_CONTROL_POWEREVENT:
1061 
1062 			if (inEventType == PBT_APMSUSPEND)
1063 			{
1064 				dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
1065 
1066 				QueueUserAPC( ( PAPCFUNC ) HandlePowerSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
1067 			}
1068 			else if (inEventType == PBT_APMRESUMESUSPEND)
1069 			{
1070 				dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1071 
1072 				QueueUserAPC( ( PAPCFUNC ) HandlePowerResumeSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
1073 			}
1074 
1075 			break;
1076 
1077 		default:
1078 			dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
1079 			break;
1080 	}
1081 
1082 	if( setStatus && gServiceStatusHandle )
1083 	{
1084 		ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1085 		check_translated_errno( ok, GetLastError(), kUnknownErr );
1086 	}
1087 
1088 	return NO_ERROR;
1089 }
1090 
1091 //===========================================================================================================================
1092 //	ServiceRun
1093 //===========================================================================================================================
1094 
ServiceRun(int argc,LPTSTR argv[])1095 static OSStatus	ServiceRun( int argc, LPTSTR argv[] )
1096 {
1097 	OSStatus		err;
1098 	BOOL			initialized;
1099 	BOOL			ok;
1100 
1101 	DEBUG_UNUSED( argc );
1102 	DEBUG_UNUSED( argv );
1103 
1104 	initialized = FALSE;
1105 
1106 	// <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1107 	// had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1108 	// We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1109 	// simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1110 	// any installers that are waiting for our state to change.
1111 
1112 	gServiceStatus.dwCurrentState = SERVICE_RUNNING;
1113 	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1114 	check_translated_errno( ok, GetLastError(), kParamErr );
1115 
1116 	// Initialize the service-specific stuff
1117 
1118 	err = ServiceSpecificInitialize( argc, argv );
1119 	require_noerr( err, exit );
1120 	initialized = TRUE;
1121 
1122 	err = CheckFirewall();
1123 	check_noerr( err );
1124 
1125 	if ( err )
1126 	{
1127 		gRetryFirewall = TRUE;
1128 	}
1129 
1130 	// Run the service-specific stuff. This does not return until the service quits or is stopped.
1131 
1132 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service started\n" );
1133 	err = ServiceSpecificRun( argc, argv );
1134 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service stopped (%d)\n", err );
1135 	require_noerr( err, exit );
1136 
1137 	// Service stopped. Clean up and we're done.
1138 
1139 exit:
1140 	if( initialized )
1141 	{
1142 		ServiceSpecificFinalize( argc, argv );
1143 	}
1144 	return( err );
1145 }
1146 
1147 //===========================================================================================================================
1148 //	ServiceStop
1149 //===========================================================================================================================
1150 
ServiceStop(void)1151 static void	ServiceStop( void )
1152 {
1153 	BOOL			ok;
1154 	OSStatus		err;
1155 
1156 	// Signal the event to cause the service to exit.
1157 
1158 	if( gServiceStatusHandle )
1159 	{
1160 		gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1161 		ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1162 		check_translated_errno( ok, GetLastError(), kParamErr );
1163 	}
1164 
1165 	err = ServiceSpecificStop();
1166 	check_noerr( err );
1167 }
1168 
1169 #if 0
1170 #pragma mark -
1171 #pragma mark == Service Specific ==
1172 #endif
1173 
1174 //===========================================================================================================================
1175 //	ServiceSpecificInitialize
1176 //===========================================================================================================================
1177 
ServiceSpecificInitialize(int argc,LPTSTR argv[])1178 static OSStatus	ServiceSpecificInitialize( int argc, LPTSTR argv[] )
1179 {
1180 	OSVERSIONINFO osInfo;
1181 	OSStatus err;
1182 	BOOL ok;
1183 
1184 	DEBUG_UNUSED( argc );
1185 	DEBUG_UNUSED( argv );
1186 
1187 	mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
1188 	mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
1189 
1190 	gPlatformStorage.registerWaitableEventFunc = RegisterWaitableEvent;
1191 	gPlatformStorage.unregisterWaitableEventFunc = UnregisterWaitableEvent;
1192 	gPlatformStorage.reportStatusFunc = ReportStatus;
1193 
1194 	err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
1195 	require_noerr( err, exit);
1196 
1197 	err = SetupNotifications();
1198 	check_noerr( err );
1199 
1200 	err = udsserver_init(mDNSNULL, 0);
1201 	require_noerr( err, exit);
1202 
1203 	//
1204 	// Get the version of Windows that we're running on
1205 	//
1206 	osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
1207 	ok = GetVersionEx( &osInfo );
1208 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1209 	require_noerr( err, exit );
1210 	gOSMajorVersion = osInfo.dwMajorVersion;
1211 	gOSMinorVersion = osInfo.dwMinorVersion;
1212 
1213 	SetLLRoute( &gMDNSRecord );
1214 
1215 exit:
1216 	if( err != kNoErr )
1217 	{
1218 		ServiceSpecificFinalize( argc, argv );
1219 	}
1220 	return( err );
1221 }
1222 
1223 //===========================================================================================================================
1224 //	ServiceSpecificRun
1225 //===========================================================================================================================
1226 
ServiceSpecificRun(int argc,LPTSTR argv[])1227 static OSStatus	ServiceSpecificRun( int argc, LPTSTR argv[] )
1228 {
1229 	HANDLE	*	waitList;
1230 	int			waitListCount;
1231 	DWORD		timeout;
1232 	DWORD		result;
1233 	BOOL		done;
1234 	mStatus		err;
1235 
1236 	DEBUG_UNUSED( argc );
1237 	DEBUG_UNUSED( argv );
1238 
1239 	timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
1240 
1241 	err = SetupInterfaceList( &gMDNSRecord );
1242 	check( !err );
1243 
1244 	err = uDNS_SetupDNSConfig( &gMDNSRecord );
1245 	check( !err );
1246 
1247 	done = FALSE;
1248 
1249 	// Main event loop.
1250 
1251 	while( !done )
1252 	{
1253 		waitList		= NULL;
1254 		waitListCount	= 0;
1255 
1256 		err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
1257 		require_noerr( err, exit );
1258 
1259 		gEventSourceListChanged = FALSE;
1260 
1261 		while ( !gEventSourceListChanged )
1262 		{
1263 			static mDNSs32 RepeatedBusy = 0;
1264 			mDNSs32 nextTimerEvent;
1265 
1266 			// Give the mDNS core a chance to do its work and determine next event time.
1267 
1268 			nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
1269 
1270 			if      ( nextTimerEvent < 0)					nextTimerEvent = 0;
1271 			else if ( nextTimerEvent > (0x7FFFFFFF / 1000))	nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
1272 			else											nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
1273 
1274 			// Debugging sanity check, to guard against CPU spins
1275 
1276 			if ( nextTimerEvent > 0 )
1277 			{
1278 				RepeatedBusy = 0;
1279 			}
1280 			else
1281 			{
1282 				nextTimerEvent = 1;
1283 
1284 				if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
1285 				{
1286 					ShowTaskSchedulingError( &gMDNSRecord );
1287 					RepeatedBusy = 0;
1288 				}
1289 			}
1290 
1291 			if ( gMDNSRecord.ShutdownTime )
1292 			{
1293 				mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
1294 
1295 				if ( mDNS_ExitNow( &gMDNSRecord, now ) )
1296 				{
1297 					mDNS_FinalExit( &gMDNSRecord );
1298 					done = TRUE;
1299 					break;
1300 				}
1301 
1302 				if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
1303 				{
1304 					nextTimerEvent = gMDNSRecord.ShutdownTime;
1305 				}
1306 			}
1307 
1308 			// Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1309 			//
1310 			// Note: There seems to be a bug in WinSock with respect to Alertable I/O. According
1311 			// to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
1312 			// callbacks will only be invoked during the following calls (when the caller sets
1313 			// the appropriate flag):
1314 			//
1315 			// - SleepEx
1316 			// - WaitForSingleObjectEx
1317 			// - WaitForMultipleObjectsEx
1318 			// - SignalObjectAndWait
1319 			// - MsgWaitForMultipleObjectsEx
1320 			//
1321 			// However, we have seen callbacks be invoked during calls to bind() (and maybe others). If there
1322 			// weren't a bug, then socket events would only be queued during the call to WaitForMultipleObjects() and
1323 			// we'd only have to check them once afterwards. However since that doesn't seem to be the case, we'll
1324 			// check the queue both before we call WaitForMultipleObjects() and after.
1325 
1326 			DispatchSocketEvents( &gMDNSRecord );
1327 			result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) nextTimerEvent, TRUE );
1328 			check( result != WAIT_FAILED );
1329 			DispatchSocketEvents( &gMDNSRecord );
1330 
1331 			if ( result != WAIT_FAILED )
1332 			{
1333 				if ( result == WAIT_TIMEOUT )
1334 				{
1335 					// Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1336 
1337 					dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
1338 					continue;
1339 				}
1340 				else if ( result == WAIT_IO_COMPLETION )
1341 				{
1342 					dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
1343 					continue;
1344 				}
1345 				else if ( result == kWaitListStopEvent )
1346 				{
1347 					// Stop event. Set the done flag and break to exit.
1348 
1349 					dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
1350 					udsserver_exit();
1351 					mDNS_StartExit( &gMDNSRecord );
1352 					break;
1353 				}
1354 				else if( result == kWaitListInterfaceListChangedEvent )
1355 				{
1356 					int		inBuffer;
1357 					int		outBuffer;
1358 					DWORD	outSize;
1359 
1360 					// It would be nice to come up with a more elegant solution to this, but it seems that
1361 					// GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
1362 					// as a simple workaround, we'll pause for a couple of seconds before processing the change.
1363 
1364 					// We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1365 					// for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
1366 					// second on top of that to account for machine load or some other exigency.
1367 
1368 					Sleep( 2000 );
1369 
1370 					// Interface list changed event. Break out of the inner loop to re-setup the wait list.
1371 
1372 					InterfaceListDidChange( &gMDNSRecord );
1373 
1374 					// reset the event handler
1375 					inBuffer	= 0;
1376 					outBuffer	= 0;
1377 					err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1378 					if( err < 0 )
1379 					{
1380 						check( errno_compat() == WSAEWOULDBLOCK );
1381 					}
1382 				}
1383 				else if ( result == kWaitListComputerDescriptionEvent )
1384 				{
1385 					// The computer description might have changed
1386 
1387 					ComputerDescriptionDidChange( &gMDNSRecord );
1388 					udsserver_handle_configchange( &gMDNSRecord );
1389 
1390 					// and reset the event handler
1391 					if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
1392 					{
1393 						err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1394 						check_noerr( err );
1395 					}
1396 				}
1397 				else if ( result == kWaitListTCPIPEvent )
1398 				{
1399 					// The TCP/IP might have changed
1400 
1401 					TCPIPConfigDidChange( &gMDNSRecord );
1402 					udsserver_handle_configchange( &gMDNSRecord );
1403 
1404 					// and reset the event handler
1405 
1406 					if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
1407 					{
1408 						err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
1409 						check_noerr( err );
1410 					}
1411 				}
1412 				else if ( result == kWaitListDynDNSEvent )
1413 				{
1414 					// The DynDNS config might have changed
1415 
1416 					DynDNSConfigDidChange( &gMDNSRecord );
1417 					udsserver_handle_configchange( &gMDNSRecord );
1418 
1419 					// and reset the event handler
1420 
1421 					if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
1422 					{
1423 						err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1424 						check_noerr( err );
1425 					}
1426 				}
1427 				else if ( result == kWaitListFileShareEvent )
1428 				{
1429 					// File sharing changed
1430 
1431 					FileSharingDidChange( &gMDNSRecord );
1432 
1433 					// and reset the event handler
1434 
1435 					if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
1436 					{
1437 						err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1438 						check_noerr( err );
1439 					}
1440 				}
1441 				else if ( result == kWaitListFirewallEvent )
1442 				{
1443 					// Firewall configuration changed
1444 
1445 					FirewallDidChange( &gMDNSRecord );
1446 
1447 					// and reset the event handler
1448 
1449 					if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
1450 					{
1451 						err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1452 						check_noerr( err );
1453 					}
1454 				}
1455 				else if ( result == kWaitListAdvertisedServicesEvent )
1456 				{
1457 					// Ultimately we'll want to manage multiple services, but right now the only service
1458 					// we'll be managing is SMB.
1459 
1460 					FileSharingDidChange( &gMDNSRecord );
1461 
1462 					// and reset the event handler
1463 
1464 					if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
1465 					{
1466 						err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1467 						check_noerr( err );
1468 					}
1469 				}
1470 				else if ( result == kWaitListSPSWakeupEvent )
1471 				{
1472 					LARGE_INTEGER timeout;
1473 
1474 					ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
1475 
1476 					timeout.QuadPart  = kSPSMaintenanceWakePeriod;
1477 					timeout.QuadPart *= kSecondsTo100NSUnits;
1478 
1479 					SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
1480 				}
1481 				else if ( result == kWaitListSPSSleepEvent )
1482 				{
1483 					ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
1484 
1485 					// Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1486 					// call HandlePowerSuspend() explicity.  This will reset the
1487 					// maintenance wake timers.
1488 
1489 					HandlePowerSuspend( NULL );
1490 					SetSuspendState( FALSE, FALSE, FALSE );
1491 				}
1492 				else
1493 				{
1494 					int waitItemIndex;
1495 
1496 					waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
1497 					dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
1498 					check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
1499 
1500 					if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
1501 					{
1502 						HANDLE	signaledEvent;
1503 						int		n = 0;
1504 
1505 						signaledEvent = waitList[ waitItemIndex ];
1506 
1507 						// If gCurrentSource is not NULL, then this routine has been called
1508 						// re-entrantly which should never happen.
1509 
1510 						check( !gCurrentSource );
1511 
1512 						for ( gCurrentSource = gEventSourceList; gCurrentSource; )
1513 						{
1514 							EventSource * current = gCurrentSource;
1515 
1516 							if ( gCurrentSource->event == signaledEvent )
1517 							{
1518 								gCurrentSource->handler( &gMDNSRecord, gCurrentSource->event, gCurrentSource->context );
1519 								++n;
1520 								break;
1521 							}
1522 
1523 							// If the current node was removed as a result of calling
1524 							// the handler, then gCurrentSource was already incremented to
1525 							// the next node.  If it wasn't removed, then increment it
1526 							// ourselves
1527 
1528 							if ( gCurrentSource == current )
1529 							{
1530 								gCurrentSource = gCurrentSource->next;
1531 							}
1532 						}
1533 
1534 						gCurrentSource = NULL;
1535 
1536 						check( n > 0 );
1537 					}
1538 					else
1539 					{
1540 						dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1541 					}
1542 				}
1543 			}
1544 			else
1545 			{
1546 				Sleep( 3 * 1000 );
1547 
1548 				err = SetupInterfaceList( &gMDNSRecord );
1549 				check( !err );
1550 
1551 				err = uDNS_SetupDNSConfig( &gMDNSRecord );
1552 				check( !err );
1553 
1554 				break;
1555 			}
1556 		}
1557 
1558 		if ( waitList )
1559 		{
1560 			free( waitList );
1561 			waitList = NULL;
1562 			waitListCount = 0;
1563 		}
1564 	}
1565 
1566 exit:
1567 
1568 	return( 0 );
1569 }
1570 
1571 //===========================================================================================================================
1572 //	ServiceSpecificStop
1573 //===========================================================================================================================
1574 
ServiceSpecificStop(void)1575 static OSStatus	ServiceSpecificStop( void )
1576 {
1577 	OSStatus	err;
1578 	BOOL	 	ok;
1579 
1580 	ok = SetEvent(gStopEvent);
1581 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1582 	require_noerr( err, exit );
1583 exit:
1584 	return( err );
1585 }
1586 
1587 //===========================================================================================================================
1588 //	ServiceSpecificFinalize
1589 //===========================================================================================================================
1590 
ServiceSpecificFinalize(int argc,LPTSTR argv[])1591 static void	ServiceSpecificFinalize( int argc, LPTSTR argv[] )
1592 {
1593 	DEBUG_UNUSED( argc );
1594 	DEBUG_UNUSED( argv );
1595 
1596 	//
1597 	// clean up any open sessions
1598 	//
1599 	while ( gEventSourceList )
1600 	{
1601 		UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
1602 	}
1603 
1604 	//
1605 	// clean up the notifications
1606 	//
1607 	TearDownNotifications();
1608 
1609 	//
1610 	// clean up loaded library
1611 	//
1612 
1613 	if( gIPHelperLibraryInstance )
1614 	{
1615 		gGetIpInterfaceEntryFunctionPtr = NULL;
1616 
1617 		FreeLibrary( gIPHelperLibraryInstance );
1618 		gIPHelperLibraryInstance = NULL;
1619 	}
1620 }
1621 
1622 
1623 //===========================================================================================================================
1624 //	SetupNotifications
1625 //===========================================================================================================================
1626 
SetupNotifications()1627 mDNSlocal mStatus	SetupNotifications()
1628 {
1629 	mStatus				err;
1630 	SocketRef			sock;
1631 	unsigned long		param;
1632 	int					inBuffer;
1633 	int					outBuffer;
1634 	DWORD				outSize;
1635 
1636 	gStopEvent	=	CreateEvent(NULL, FALSE, FALSE, NULL);
1637 	err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
1638 	require_noerr( err, exit );
1639 
1640 	// Register to listen for address list changes.
1641 
1642 	gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1643 	err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1644 	require_noerr( err, exit );
1645 
1646 	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1647 	err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1648 	require_noerr( err, exit );
1649 	gInterfaceListChangedSocket = sock;
1650 
1651 	// Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1652 	// when a change to the interface list is detected.
1653 
1654 	param = 1;
1655 	err = ioctlsocket( sock, FIONBIO, &param );
1656 	err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1657 	require_noerr( err, exit );
1658 
1659 	inBuffer	= 0;
1660 	outBuffer	= 0;
1661 	err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1662 	if( err < 0 )
1663 	{
1664 		check( errno_compat() == WSAEWOULDBLOCK );
1665 	}
1666 
1667 	err = WSAEventSelect( sock, gInterfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
1668 	err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1669 	require_noerr( err, exit );
1670 
1671 	gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1672 	err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1673 	require_noerr( err, exit );
1674 
1675 	err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
1676 	check_translated_errno( err == 0, errno_compat(), kNameErr );
1677 
1678 	if ( gDescKey != NULL )
1679 	{
1680 		err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1681 		require_noerr( err, exit );
1682 	}
1683 
1684 	// This will catch all changes to tcp/ip networking, including changes to the domain search list
1685 
1686 	gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1687 	err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1688 	require_noerr( err, exit );
1689 
1690 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
1691 	require_noerr( err, exit );
1692 
1693 	err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
1694 	require_noerr( err, exit );
1695 
1696 	// This will catch all changes to ddns configuration
1697 
1698 	gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1699 	err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1700 	require_noerr( err, exit );
1701 
1702 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
1703 	require_noerr( err, exit );
1704 
1705 	err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1706 	require_noerr( err, exit );
1707 
1708 	// This will catch all changes to file sharing
1709 
1710 	gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1711 	err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1712 	require_noerr( err, exit );
1713 
1714 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
1715 
1716 	// Just to make sure that initialization doesn't fail on some old OS
1717 	// that doesn't have this key, we'll only add the notification if
1718 	// the key exists.
1719 
1720 	if ( !err )
1721 	{
1722 		err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1723 		require_noerr( err, exit );
1724 	}
1725 	else
1726 	{
1727 		err = mStatus_NoError;
1728 	}
1729 
1730 	// This will catch changes to the Windows firewall
1731 
1732 	gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1733 	err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1734 	require_noerr( err, exit );
1735 
1736 	// Just to make sure that initialization doesn't fail on some old OS
1737 	// that doesn't have this key, we'll only add the notification if
1738 	// the key exists.
1739 
1740 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
1741 
1742 	if ( !err )
1743 	{
1744 		err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1745 		require_noerr( err, exit );
1746 	}
1747 	else
1748 	{
1749 		err = mStatus_NoError;
1750 	}
1751 
1752 	// This will catch all changes to advertised services configuration
1753 
1754 	gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1755 	err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1756 	require_noerr( err, exit );
1757 
1758 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
1759 	require_noerr( err, exit );
1760 
1761 	err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1762 	require_noerr( err, exit );
1763 
1764 	gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1765 	err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
1766 	require_noerr( err, exit );
1767 
1768 	gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1769 	err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
1770 	require_noerr( err, exit );
1771 
1772 	gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1773 	err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
1774 	require_noerr( err, exit );
1775 
1776 exit:
1777 	if( err )
1778 	{
1779 		TearDownNotifications();
1780 	}
1781 	return( err );
1782 }
1783 
1784 //===========================================================================================================================
1785 //	TearDownNotifications
1786 //===========================================================================================================================
1787 
TearDownNotifications()1788 mDNSlocal mStatus	TearDownNotifications()
1789 {
1790 	if ( gStopEvent )
1791 	{
1792 		CloseHandle( gStopEvent );
1793 		gStopEvent = NULL;
1794 	}
1795 
1796 	if( IsValidSocket( gInterfaceListChangedSocket ) )
1797 	{
1798 		close_compat( gInterfaceListChangedSocket );
1799 		gInterfaceListChangedSocket = kInvalidSocketRef;
1800 	}
1801 
1802 	if( gInterfaceListChangedEvent )
1803 	{
1804 		CloseHandle( gInterfaceListChangedEvent );
1805 		gInterfaceListChangedEvent = 0;
1806 	}
1807 
1808 	if ( gDescChangedEvent != NULL )
1809 	{
1810 		CloseHandle( gDescChangedEvent );
1811 		gDescChangedEvent = NULL;
1812 	}
1813 
1814 	if ( gDescKey != NULL )
1815 	{
1816 		RegCloseKey( gDescKey );
1817 		gDescKey = NULL;
1818 	}
1819 
1820 	if ( gTcpipChangedEvent != NULL )
1821 	{
1822 		CloseHandle( gTcpipChangedEvent );
1823 		gTcpipChangedEvent = NULL;
1824 	}
1825 
1826 	if ( gDdnsChangedEvent != NULL )
1827 	{
1828 		CloseHandle( gDdnsChangedEvent );
1829 		gDdnsChangedEvent = NULL;
1830 	}
1831 
1832 	if ( gDdnsKey != NULL )
1833 	{
1834 		RegCloseKey( gDdnsKey );
1835 		gDdnsKey = NULL;
1836 	}
1837 
1838 	if ( gFileSharingChangedEvent != NULL )
1839 	{
1840 		CloseHandle( gFileSharingChangedEvent );
1841 		gFileSharingChangedEvent = NULL;
1842 	}
1843 
1844 	if ( gFileSharingKey != NULL )
1845 	{
1846 		RegCloseKey( gFileSharingKey );
1847 		gFileSharingKey = NULL;
1848 	}
1849 
1850 	if ( gFirewallChangedEvent != NULL )
1851 	{
1852 		CloseHandle( gFirewallChangedEvent );
1853 		gFirewallChangedEvent = NULL;
1854 	}
1855 
1856 	if ( gFirewallKey != NULL )
1857 	{
1858 		RegCloseKey( gFirewallKey );
1859 		gFirewallKey = NULL;
1860 	}
1861 
1862 	if ( gAdvertisedServicesChangedEvent != NULL )
1863 	{
1864 		CloseHandle( gAdvertisedServicesChangedEvent );
1865 		gAdvertisedServicesChangedEvent = NULL;
1866 	}
1867 
1868 	if ( gAdvertisedServicesKey != NULL )
1869 	{
1870 		RegCloseKey( gAdvertisedServicesKey );
1871 		gAdvertisedServicesKey = NULL;
1872 	}
1873 
1874 	if ( gSPSWakeupEvent )
1875 	{
1876 		CloseHandle( gSPSWakeupEvent );
1877 		gSPSWakeupEvent = NULL;
1878 	}
1879 
1880 	if ( gSPSSleepEvent )
1881 	{
1882 		CloseHandle( gSPSSleepEvent );
1883 		gSPSSleepEvent = NULL;
1884 	}
1885 
1886 	return( mStatus_NoError );
1887 }
1888 
1889 
1890 //===========================================================================================================================
1891 //	RegisterWaitableEvent
1892 //===========================================================================================================================
1893 
RegisterWaitableEvent(mDNS * const inMDNS,HANDLE event,void * context,RegisterWaitableEventHandler handler)1894 static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
1895 {
1896 	EventSource * source;
1897 	mStatus err = mStatus_NoError;
1898 
1899 	( void ) inMDNS;
1900 	check( event );
1901 	check( handler );
1902 
1903 	source = ( EventSource* ) malloc( sizeof( EventSource ) );
1904 	require_action( source, exit, err = mStatus_NoMemoryErr );
1905 	mDNSPlatformMemZero( source, sizeof( EventSource ) );
1906 	source->event = event;
1907 	source->context = context;
1908 	source->handler = handler;
1909 
1910 	source->next			= gEventSourceList;
1911 	gEventSourceList		= source;
1912 	gEventSourceListChanged	= TRUE;
1913 	gEventSources++;
1914 
1915 exit:
1916 
1917 	return err;
1918 }
1919 
1920 
1921 //===========================================================================================================================
1922 //	UnregisterWaitableEvent
1923 //===========================================================================================================================
1924 
UnregisterWaitableEvent(mDNS * const inMDNS,HANDLE event)1925 static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
1926 {
1927 	EventSource	*	current	= gEventSourceList;
1928 	EventSource	*	last	= NULL;
1929 
1930 	( void ) inMDNS;
1931 	check( event );
1932 
1933 	while ( current )
1934 	{
1935 		if ( current->event == event )
1936 		{
1937 			if ( last == NULL )
1938 			{
1939 				gEventSourceList = current->next;
1940 			}
1941 			else
1942 			{
1943 				last->next = current->next;
1944 			}
1945 
1946 			gEventSourceListChanged = TRUE;
1947 
1948 			// Protect against removing the node that we happen
1949 			// to be looking at as we iterate through the event
1950 			// source list in ServiceSpecificRun()
1951 
1952 			if ( current == gCurrentSource )
1953 			{
1954 				gCurrentSource = current->next;
1955 			}
1956 
1957 			gEventSources--;
1958 			free( current );
1959 
1960 			break;
1961 		}
1962 
1963 		last	= current;
1964 		current	= current->next;
1965 	}
1966 }
1967 
1968 
1969 //===========================================================================================================================
1970 //	SetupWaitList
1971 //===========================================================================================================================
1972 
SetupWaitList(mDNS * const inMDNS,HANDLE ** outWaitList,int * outWaitListCount)1973 mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
1974 {
1975 	int				waitListCount;
1976 	HANDLE		*	waitList;
1977 	HANDLE		*	waitItemPtr;
1978 	EventSource	*	source;
1979 	mStatus			err;
1980 
1981 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
1982 
1983 	( void ) inMDNS;
1984 	check( inMDNS->p );
1985 	check( outWaitList );
1986 	check( outWaitListCount );
1987 
1988 	// Allocate an array to hold all the objects to wait on.
1989 
1990 	waitListCount = kWaitListFixedItemCount + gEventSources;
1991 	waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
1992 	require_action( waitList, exit, err = mStatus_NoMemoryErr );
1993 	waitItemPtr = waitList;
1994 
1995 	// Add the fixed wait items to the beginning of the list.
1996 
1997 	*waitItemPtr++	=	gStopEvent;
1998 	*waitItemPtr++	=	gInterfaceListChangedEvent;
1999 	*waitItemPtr++	=	gDescChangedEvent;
2000 	*waitItemPtr++	=	gTcpipChangedEvent;
2001 	*waitItemPtr++	=	gDdnsChangedEvent;
2002 	*waitItemPtr++	=	gFileSharingChangedEvent;
2003 	*waitItemPtr++	=	gFirewallChangedEvent;
2004 	*waitItemPtr++	=	gAdvertisedServicesChangedEvent;
2005 	*waitItemPtr++	=	gSPSWakeupEvent;
2006 	*waitItemPtr++	=	gSPSSleepEvent;
2007 
2008 	for ( source = gEventSourceList; source; source = source->next )
2009 	{
2010 		*waitItemPtr++ = source->event;
2011 	}
2012 
2013 	check( ( int )( waitItemPtr - waitList ) == waitListCount );
2014 
2015 	*outWaitList 		= waitList;
2016 	*outWaitListCount	= waitListCount;
2017 	waitList			= NULL;
2018 	err					= mStatus_NoError;
2019 
2020 exit:
2021 
2022 	if( waitList )
2023 	{
2024 		free( waitList );
2025 	}
2026 
2027 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
2028 	return( err );
2029 }
2030 
2031 
2032 //===========================================================================================================================
2033 //	CoreCallback
2034 //===========================================================================================================================
2035 
2036 static void
CoreCallback(mDNS * const inMDNS,mStatus status)2037 CoreCallback(mDNS * const inMDNS, mStatus status)
2038 {
2039 	if (status == mStatus_ConfigChanged)
2040 	{
2041 		SetLLRoute( inMDNS );
2042 	}
2043 }
2044 
2045 
2046 //===========================================================================================================================
2047 //	UDSCanAccept
2048 //===========================================================================================================================
2049 
UDSCanAccept(mDNS * const inMDNS,HANDLE event,void * context)2050 mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
2051 {
2052 	( void ) inMDNS;
2053 	( void ) event;
2054 
2055 	if ( gUDSCallback )
2056 	{
2057 		gUDSCallback( ( int ) gUDSSocket, 0, context );
2058 	}
2059 }
2060 
2061 
2062 //===========================================================================================================================
2063 //	UDSCanRead
2064 //===========================================================================================================================
2065 
UDSCanRead(TCPSocket * sock)2066 mDNSlocal void UDSCanRead( TCPSocket * sock )
2067 {
2068 	udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
2069 
2070 	if ( callback )
2071 	{
2072 		callback( (int) sock->fd, 0, sock->userContext );
2073 	}
2074 }
2075 
2076 
2077 //===========================================================================================================================
2078 //	udsSupportAddFDToEventLoop
2079 //===========================================================================================================================
2080 
2081 
2082 mStatus
udsSupportAddFDToEventLoop(SocketRef fd,udsEventCallback callback,void * context,void ** platform_data)2083 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
2084 {
2085 	mStatus err = mStatus_NoError;
2086 
2087 	// We are using some knowledge of what is being passed to us here.  If the fd is a listen socket,
2088 	// then the "callback" parameter is NULL.  If it is an actual read/write socket, then the "callback"
2089 	// parameter is not null. This is important because we use waitable events for the listen socket
2090 	// and alertable I/O for the read/write sockets.
2091 
2092 	if ( context )
2093 	{
2094 		TCPSocket * sock;
2095 
2096 		sock = malloc( sizeof( TCPSocket ) );
2097 		require_action( sock, exit, err = mStatus_NoMemoryErr );
2098 		mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
2099 
2100 		sock->fd				= (SOCKET) fd;
2101 		sock->readEventHandler	= UDSCanRead;
2102 		sock->userCallback		= callback;
2103 		sock->userContext		= context;
2104 		sock->m					= &gMDNSRecord;
2105 
2106 		err = TCPAddSocket( sock->m, sock );
2107 		require_noerr( err, exit );
2108 
2109 		*platform_data = sock;
2110 	}
2111 	else
2112 	{
2113 		gUDSSocket		= fd;
2114 		gUDSCallback	= callback;
2115 		gUDSEvent		= CreateEvent( NULL, FALSE, FALSE, NULL );
2116 		err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
2117 		require_noerr( err, exit );
2118 		err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );
2119 		err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );
2120 		require_noerr( err, exit );
2121 		err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
2122 		require_noerr( err, exit );
2123 	}
2124 
2125 exit:
2126 
2127 	return err;
2128 }
2129 
2130 
2131 int
udsSupportReadFD(SocketRef fd,char * buf,int len,int flags,void * platform_data)2132 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
2133 {
2134 	TCPSocket	*	sock;
2135 	mDNSBool		closed;
2136 	int				ret;
2137 
2138 	( void ) flags;
2139 
2140 	sock = ( TCPSocket* ) platform_data;
2141 	require_action( sock, exit, ret = -1 );
2142 	require_action( sock->fd == fd, exit, ret = -1 );
2143 
2144 	ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
2145 
2146 	if ( closed )
2147 	{
2148 		ret = 0;
2149 	}
2150 
2151 exit:
2152 
2153 	return ret;
2154 }
2155 
2156 
2157 mStatus
udsSupportRemoveFDFromEventLoop(SocketRef fd,void * platform_data)2158 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)		// Note: This also CLOSES the socket
2159 {
2160 	mStatus err = kNoErr;
2161 
2162 	if ( platform_data != NULL )
2163 	{
2164 		TCPSocket * sock;
2165 
2166 		dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
2167 		sock = ( TCPSocket* ) platform_data;
2168 		check( sock->fd == fd );
2169 		mDNSPlatformTCPCloseConnection( sock );
2170 	}
2171 	else if ( gUDSEvent != NULL )
2172 	{
2173 		UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
2174 		WSAEventSelect( fd, gUDSEvent, 0 );
2175 		CloseHandle( gUDSEvent );
2176 		gUDSEvent = NULL;
2177 	}
2178 
2179 	return err;
2180 }
2181 
2182 
RecordUpdatedNiceLabel(mDNS * const m,mDNSs32 delay)2183 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
2184 	{
2185 	(void)m;
2186 	(void)delay;
2187 	// No-op, for now
2188 	}
2189 
2190 
2191 //===========================================================================================================================
2192 //	SystemWakeForNetworkAccess
2193 //===========================================================================================================================
2194 
2195 mDNSu8
SystemWakeForNetworkAccess(LARGE_INTEGER * timeout)2196 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
2197 {
2198 	HKEY					key = NULL;
2199 	DWORD					dwSize;
2200 	DWORD					enabled;
2201 	mDNSu8					ok;
2202 	SYSTEM_POWER_STATUS		powerStatus;
2203 	time_t					startTime;
2204 	time_t					nextWakeupTime;
2205 	int						delta;
2206 	DWORD					err;
2207 
2208 	dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
2209 
2210 	// Make sure we have a timer
2211 
2212 	require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
2213 	require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
2214 
2215 	// Make sure the user enabled bonjour sleep proxy client
2216 
2217 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
2218 	require_action( !err, exit, ok = FALSE );
2219 	dwSize = sizeof( DWORD );
2220 	err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
2221 	require_action( !err, exit, ok = FALSE );
2222 	require_action( enabled, exit, ok = FALSE );
2223 
2224 	// Make sure machine is on AC power
2225 
2226 	ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
2227 	require_action( ok, exit, ok = FALSE );
2228 	require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
2229 
2230 	// Now make sure we have a network interface that does wake-on-lan
2231 
2232 	ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
2233 	require_action( ok, exit, ok = FALSE );
2234 
2235 	// Now make sure we have advertised services. Doesn't make sense to
2236 	// enable sleep proxy if we have no multicast services that could
2237 	// potentially wake us up.
2238 
2239 	ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
2240 	require_action( ok, exit, ok = FALSE );
2241 
2242 	// Calculate next wake up time
2243 
2244 	startTime		= time( NULL );					// Seconds since midnight January 1, 1970
2245 	nextWakeupTime	= startTime + ( 120 * 60 );		// 2 hours later
2246 
2247 	if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
2248 	{
2249 		nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
2250 	}
2251 
2252 	// Finally calculate the next relative wakeup time
2253 
2254 	delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
2255 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
2256 
2257 	// Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2258 
2259 	timeout->QuadPart  = -delta;
2260 	timeout->QuadPart *= kSecondsTo100NSUnits;
2261 
2262 	ok = TRUE;
2263 
2264 exit:
2265 
2266 	if ( key )
2267 	{
2268 		RegCloseKey( key );
2269 	}
2270 
2271 	return ok;
2272 }
2273 
2274 
2275 //===========================================================================================================================
2276 //	HaveRoute
2277 //===========================================================================================================================
2278 
2279 static bool
HaveRoute(PMIB_IPFORWARDROW rowExtant,unsigned long addr,unsigned long metric)2280 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
2281 {
2282 	PMIB_IPFORWARDTABLE	pIpForwardTable	= NULL;
2283 	DWORD				dwSize			= 0;
2284 	BOOL				bOrder			= FALSE;
2285 	OSStatus			err;
2286 	bool				found			= false;
2287 	unsigned long int	i;
2288 
2289 	//
2290 	// Find out how big our buffer needs to be.
2291 	//
2292 	err = GetIpForwardTable(NULL, &dwSize, bOrder);
2293 	require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
2294 
2295 	//
2296 	// Allocate the memory for the table
2297 	//
2298 	pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
2299 	require_action( pIpForwardTable, exit, err = kNoMemoryErr );
2300 
2301 	//
2302 	// Now get the table.
2303 	//
2304 	err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
2305 	require_noerr( err, exit );
2306 
2307 	//
2308 	// Search for the row in the table we want.
2309 	//
2310 	for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
2311 	{
2312 		if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
2313 		{
2314 			memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
2315 			found = true;
2316 			break;
2317 		}
2318 	}
2319 
2320 exit:
2321 
2322 	if ( pIpForwardTable != NULL )
2323 	{
2324 		free(pIpForwardTable);
2325 	}
2326 
2327 	return found;
2328 }
2329 
2330 
2331 //===========================================================================================================================
2332 //	IsValidAddress
2333 //===========================================================================================================================
2334 
2335 static bool
IsValidAddress(const char * addr)2336 IsValidAddress( const char * addr )
2337 {
2338 	return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2339 }
2340 
2341 
2342 //===========================================================================================================================
2343 //	GetAdditionalMetric
2344 //===========================================================================================================================
2345 
2346 static ULONG
GetAdditionalMetric(DWORD ifIndex)2347 GetAdditionalMetric( DWORD ifIndex )
2348 {
2349 	ULONG metric = 0;
2350 
2351 	if( !gIPHelperLibraryInstance )
2352 	{
2353 		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2354 
2355 		gGetIpInterfaceEntryFunctionPtr =
2356 				(GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
2357 
2358 		if( !gGetIpInterfaceEntryFunctionPtr )
2359 		{
2360 			BOOL ok;
2361 
2362 			ok = FreeLibrary( gIPHelperLibraryInstance );
2363 			check_translated_errno( ok, GetLastError(), kUnknownErr );
2364 			gIPHelperLibraryInstance = NULL;
2365 		}
2366 	}
2367 
2368 	if ( gGetIpInterfaceEntryFunctionPtr )
2369 	{
2370 		MIB_IPINTERFACE_ROW row;
2371 		DWORD err;
2372 
2373 		ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
2374 		row.Family = AF_INET;
2375 		row.InterfaceIndex = ifIndex;
2376 		err = gGetIpInterfaceEntryFunctionPtr( &row );
2377 		require_noerr( err, exit );
2378 		metric = row.Metric + 256;
2379 	}
2380 
2381 exit:
2382 
2383 	return metric;
2384 }
2385 
2386 
2387 //===========================================================================================================================
2388 //	SetLLRoute
2389 //===========================================================================================================================
2390 
2391 static OSStatus
SetLLRoute(mDNS * const inMDNS)2392 SetLLRoute( mDNS * const inMDNS )
2393 {
2394 	OSStatus err = kNoErr;
2395 
2396 	DEBUG_UNUSED( inMDNS );
2397 
2398 	//
2399 	// <rdar://problem/4096464> Don't call SetLLRoute on loopback
2400 	// <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2401 	//
2402 	// Don't mess w/ the routing table on Vista and later OSes, as
2403 	// they have a permanent route to link-local addresses. Otherwise,
2404 	// set a route to link local addresses (169.254.0.0)
2405 	//
2406 	if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
2407 	{
2408 		DWORD				ifIndex;
2409 		MIB_IPFORWARDROW	rowExtant;
2410 		bool				addRoute;
2411 		MIB_IPFORWARDROW	row;
2412 
2413 		ZeroMemory(&row, sizeof(row));
2414 
2415 		err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
2416 		require_noerr( err, exit );
2417 		row.dwForwardDest		= inet_addr(kLLNetworkAddr);
2418 		row.dwForwardIfIndex	= ifIndex;
2419 		row.dwForwardMask		= inet_addr(kLLNetworkAddrMask);
2420 		row.dwForwardType		= 3;
2421 		row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
2422 		row.dwForwardAge		= 0;
2423 		row.dwForwardPolicy		= 0;
2424 		row.dwForwardMetric1	= 20 + GetAdditionalMetric( ifIndex );
2425 		row.dwForwardMetric2	= (DWORD) - 1;
2426 		row.dwForwardMetric3	= (DWORD) - 1;
2427 		row.dwForwardMetric4	= (DWORD) - 1;
2428 		row.dwForwardMetric5	= (DWORD) - 1;
2429 
2430 		addRoute = true;
2431 
2432 		//
2433 		// check to make sure we don't already have a route
2434 		//
2435 		if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
2436 		{
2437 			//
2438 			// set the age to 0 so that we can do a memcmp.
2439 			//
2440 			rowExtant.dwForwardAge = 0;
2441 
2442 			//
2443 			// check to see if this route is the same as our route
2444 			//
2445 			if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
2446 			{
2447 				//
2448 				// if it isn't then delete this entry
2449 				//
2450 				DeleteIpForwardEntry(&rowExtant);
2451 			}
2452 			else
2453 			{
2454 				//
2455 				// else it is, so we don't want to create another route
2456 				//
2457 				addRoute = false;
2458 			}
2459 		}
2460 
2461 		if (addRoute && row.dwForwardNextHop)
2462 		{
2463 			err = CreateIpForwardEntry(&row);
2464 			check_noerr( err );
2465 		}
2466 	}
2467 
2468 exit:
2469 
2470 	return ( err );
2471 }
2472 
2473 
2474 //===========================================================================================================================
2475 //	GetRouteDestination
2476 //===========================================================================================================================
2477 
2478 static OSStatus
GetRouteDestination(DWORD * ifIndex,DWORD * address)2479 GetRouteDestination(DWORD * ifIndex, DWORD * address)
2480 {
2481 	struct in_addr		ia;
2482 	IP_ADAPTER_INFO	*	pAdapterInfo	=	NULL;
2483 	IP_ADAPTER_INFO	*	pAdapter		=	NULL;
2484 	ULONG				bufLen;
2485 	mDNSBool			done			=	mDNSfalse;
2486 	OSStatus			err;
2487 
2488 	//
2489 	// GetBestInterface will fail if there is no default gateway
2490 	// configured.  If that happens, we will just take the first
2491 	// interface in the list. MSDN support says there is no surefire
2492 	// way to manually determine what the best interface might
2493 	// be for a particular network address.
2494 	//
2495 	ia.s_addr	=	inet_addr(kLLNetworkAddr);
2496 	err			=	GetBestInterface(*(IPAddr*) &ia, ifIndex);
2497 
2498 	if (err)
2499 	{
2500 		*ifIndex = 0;
2501 	}
2502 
2503 	//
2504 	// Make an initial call to GetAdaptersInfo to get
2505 	// the necessary size into the bufLen variable
2506 	//
2507 	err = GetAdaptersInfo( NULL, &bufLen);
2508 	require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
2509 
2510 	pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
2511 	require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2512 
2513 	err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2514 	require_noerr( err, exit );
2515 
2516 	pAdapter	=	pAdapterInfo;
2517 	err			=	kUnknownErr;
2518 
2519 	// <rdar://problem/3718122>
2520 	// <rdar://problem/5652098>
2521 	//
2522 	// Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2523 	//
2524 	// If these interfaces are active (i.e., has a non-zero IP Address),
2525 	// then we want to disable routing table modifications.
2526 
2527 	while (pAdapter)
2528 	{
2529 		if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
2530 			 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
2531 		{
2532 			dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
2533 			goto exit;
2534 		}
2535 
2536 		pAdapter = pAdapter->Next;
2537 	}
2538 
2539 	while ( !done )
2540 	{
2541 		pAdapter	=	pAdapterInfo;
2542 		err			=	kUnknownErr;
2543 
2544 		while (pAdapter)
2545 		{
2546 			// If we don't have an interface selected, choose the first one that is of type ethernet and
2547 			// has a valid IP Address
2548 
2549 			if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
2550 			{
2551 				*address =	inet_addr( pAdapter->IpAddressList.IpAddress.String );
2552 				*ifIndex =  pAdapter->Index;
2553 				err		 =	kNoErr;
2554 				break;
2555 			}
2556 
2557 			pAdapter = pAdapter->Next;
2558 		}
2559 
2560 		// If we found the right interface, or we weren't trying to find a specific interface then we're done
2561 
2562 		if ( !err || !( *ifIndex) )
2563 		{
2564 			done = mDNStrue;
2565 		}
2566 
2567 		// Otherwise, try again by wildcarding the interface
2568 
2569 		else
2570 		{
2571 			*ifIndex = 0;
2572 		}
2573 	}
2574 
2575 exit:
2576 
2577 	if ( pAdapterInfo != NULL )
2578 	{
2579 		free( pAdapterInfo );
2580 	}
2581 
2582 	return( err );
2583 }
2584 
2585 
2586 static bool
IsNortelVPN(IP_ADAPTER_INFO * pAdapter)2587 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
2588 {
2589 	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2590 		    (pAdapter->AddressLength == 6) &&
2591 		    (pAdapter->Address[0] == 0x44) &&
2592 		    (pAdapter->Address[1] == 0x45) &&
2593 		    (pAdapter->Address[2] == 0x53) &&
2594 		    (pAdapter->Address[3] == 0x54) &&
2595 		    (pAdapter->Address[4] == 0x42) &&
2596 			(pAdapter->Address[5] == 0x00)) ? true : false;
2597 }
2598 
2599 
2600 static bool
IsJuniperVPN(IP_ADAPTER_INFO * pAdapter)2601 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2602 {
2603 	return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
2604 }
2605 
2606 
2607 static bool
IsCiscoVPN(IP_ADAPTER_INFO * pAdapter)2608 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
2609 {
2610 	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2611 		    (pAdapter->AddressLength == 6) &&
2612 		    (pAdapter->Address[0] == 0x00) &&
2613 		    (pAdapter->Address[1] == 0x05) &&
2614 		    (pAdapter->Address[2] == 0x9a) &&
2615 		    (pAdapter->Address[3] == 0x3c) &&
2616 		    (pAdapter->Address[4] == 0x7a) &&
2617 			(pAdapter->Address[5] == 0x00)) ? true : false;
2618 }
2619 
2620 
2621 static const char *
strnistr(const char * string,const char * subString,size_t max)2622 strnistr( const char * string, const char * subString, size_t max )
2623 {
2624 	size_t       subStringLen;
2625 	size_t       offset;
2626 	size_t       maxOffset;
2627 	size_t       stringLen;
2628 	const char * pPos;
2629 
2630 	if ( ( string == NULL ) || ( subString == NULL ) )
2631 	{
2632 		return string;
2633 	}
2634 
2635 	stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
2636 
2637 	if ( stringLen == 0 )
2638 	{
2639 		return NULL;
2640 	}
2641 
2642 	subStringLen = strlen( subString );
2643 
2644 	if ( subStringLen == 0 )
2645 	{
2646 		return string;
2647 	}
2648 
2649 	if ( subStringLen > stringLen )
2650 	{
2651 		return NULL;
2652 	}
2653 
2654 	maxOffset = stringLen - subStringLen;
2655 	pPos      = string;
2656 
2657 	for ( offset = 0; offset <= maxOffset; offset++ )
2658 	{
2659 		if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
2660 		{
2661 			return pPos;
2662 		}
2663 
2664 		pPos++;
2665 	}
2666 
2667 	return NULL;
2668 }
2669 
2670