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