Skip to content

Commit

Permalink
[W32TIME] Implement w32time service. CORE-13001
Browse files Browse the repository at this point in the history
  • Loading branch information
Doug-Lyons authored and ThFabba committed Jul 7, 2019
1 parent 119c99e commit e4898e6
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 110 deletions.
6 changes: 2 additions & 4 deletions base/services/w32time/ntpclient.c
@@ -1,10 +1,8 @@
/*
* PROJECT: ReactOS Timedate Control Panel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/cpl/timedate/ntpclient.c
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Queries the NTP server
* COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
*
*/

#include "w32time.h"
Expand Down Expand Up @@ -81,7 +79,7 @@ SendData(PINFO pInfo)
INT Ret;

ZeroMemory(&pInfo->SendPacket, sizeof(pInfo->SendPacket));
pInfo->SendPacket.LiVnMode = 27;
pInfo->SendPacket.LiVnMode = 0x1b; /* 0x1b = 011 011 - version 3 , mode 3 (client) */
if (!GetTransmitTime(&tp))
return FALSE;
pInfo->SendPacket.TransmitTimestamp = tp;
Expand Down
312 changes: 207 additions & 105 deletions base/services/w32time/w32time.c
@@ -1,107 +1,20 @@
/*
* PROJECT: ReactOS Timedate Control Panel
* PROJECT: ReactOS W32Time Service
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Create W32Time Service that reqularly syncs clock to Internet Time
* COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
* Copyright 2018 Doug Lyons
*/

#include "w32time.h"
#include <debug.h>
#include <strsafe.h>

/* Get the domain name from the registry */
static DWORD
GetNTPServerAddress(LPWSTR *lpAddress)
{
HKEY hKey;
WCHAR szSel[4];
DWORD dwSize;
LONG lRet;

*lpAddress = NULL;
hKey = NULL;

lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\DateTime\\Servers",
0,
KEY_QUERY_VALUE,
&hKey);
if (lRet != ERROR_SUCCESS)
goto Exit;

/* Get data from default value */
dwSize = 4 * sizeof(WCHAR);
lRet = RegQueryValueExW(hKey,
NULL,
NULL,
NULL,
(LPBYTE)szSel,
&dwSize);
if (lRet != ERROR_SUCCESS)
goto Exit;

dwSize = 0;
lRet = RegQueryValueExW(hKey,
szSel,
NULL,
NULL,
NULL,
&dwSize);
if (lRet != ERROR_SUCCESS)
goto Exit;

(*lpAddress) = (LPWSTR)HeapAlloc(GetProcessHeap(),
0,
dwSize);
if ((*lpAddress) == NULL)
{
lRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}

lRet = RegQueryValueExW(hKey,
szSel,
NULL,
NULL,
(LPBYTE)*lpAddress,
&dwSize);
if (lRet != ERROR_SUCCESS)
goto Exit;

Exit:
if (hKey)
RegCloseKey(hKey);
if (lRet != ERROR_SUCCESS)
HeapFree(GetProcessHeap(), 0, *lpAddress);

return lRet;
}


/* Request the time from the current NTP server */
static DWORD
GetTimeFromServer(PULONG pulTime)
{
LPWSTR lpAddress;
DWORD dwError;

dwError = GetNTPServerAddress(&lpAddress);
if (dwError != ERROR_SUCCESS)
{
return dwError;
}

*pulTime = GetServerTime(lpAddress);
if (*pulTime == 0)
{
dwError = ERROR_GEN_FAILURE;
}

HeapFree(GetProcessHeap(),
0,
lpAddress);

return dwError;
}
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
static WCHAR ServiceName[] = L"W32Time";

int InitService(VOID);

BOOL
SystemSetTime(LPSYSTEMTIME lpSystemTime)
Expand Down Expand Up @@ -207,25 +120,214 @@ UpdateSystemTime(ULONG ulTime)
}


DWORD WINAPI
W32TimeSyncNow(LPCWSTR cmdline,
UINT blocking,
UINT flags)
static DWORD
GetIntervalSetting(VOID)
{
HKEY hKey;
DWORD dwData;
DWORD dwSize = sizeof(dwData);
LONG lRet;

dwData = 0;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\W32Time\\TimeProviders\\NtpClient",
0,
KEY_QUERY_VALUE,
&hKey) == ERROR_SUCCESS)
{
/* This key holds the update interval in seconds
* It is useful for testing to set it to a value of 10 (Decimal)
* This will cause the clock to try and update every 10 seconds
* So you can change the time and expect it to be set back correctly in 10-20 seconds
*/
lRet = RegQueryValueExW(hKey,
L"SpecialPollInterval",
NULL,
NULL,
(LPBYTE)&dwData,
&dwSize);
RegCloseKey(hKey);
}

if (lRet != ERROR_SUCCESS)
return 0;
else
return dwData;
}


DWORD
SetTime(VOID)
{
DWORD dwError;
ULONG ulTime;
LONG lRet;
HKEY hKey;
WCHAR szData[MAX_VALUE_NAME] = L"";
DWORD cbName = sizeof(szData);

DPRINT("Entered SetTime.\n");

dwError = GetTimeFromServer(&ulTime);
if (dwError != ERROR_SUCCESS)
lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\DateTime\\Servers",
0,
KEY_QUERY_VALUE,
&hKey);
if (lRet != ERROR_SUCCESS)
{
return lRet;
}

lRet = RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)szData, &cbName);
if (lRet == ERROR_SUCCESS)
{
return dwError;
cbName = sizeof(szData);
lRet = RegQueryValueExW(hKey, szData, NULL, NULL, (LPBYTE)szData, &cbName);
}

RegCloseKey(hKey);

DPRINT("Time Server is '%S'.\n", szData);

ulTime = GetServerTime(szData);

if (ulTime != 0)
{
dwError = UpdateSystemTime(ulTime);
return UpdateSystemTime(ulTime);
}
else
return ERROR_GEN_FAILURE;
}

return dwError;

/* Control handler function */
VOID WINAPI
ControlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
DPRINT("W32Time Service stopped.\n");

ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
return;

case SERVICE_CONTROL_SHUTDOWN:
DPRINT("W32Time Service stopped.\n");

ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);
return;

default:
break;
}

/* Report current status */
SetServiceStatus(hStatus, &ServiceStatus);

return;
}


VOID
WINAPI
ServiceMain(DWORD argc, LPWSTR *argv)
{
int result;
DWORD dwPollInterval;

UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);

ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;

hStatus = RegisterServiceCtrlHandlerW(ServiceName,
ControlHandler);
if (!hStatus)
{
/* Registering Control Handler failed */
return;
}

/* We report the running status to SCM. */
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);

/* The worker loop of a service */
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
dwPollInterval = GetIntervalSetting();
result = SetTime();

if (result)
DPRINT("W32Time Service failed to set clock.\n");
else
DPRINT("W32Time Service successfully set clock.\n");

if (result)
{
/* In general we do not want to stop this service for a single
* Internet read failure but there may be other reasons for which
* we really might want to stop it.
* Therefore this code is left here to make it easy to stop this
* service when the correct conditions can be determined, but it
* is left commented out.
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
*/
}

Sleep(dwPollInterval * 1000);
}
return;
}



BOOL WINAPI
DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
break;

case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}


DWORD WINAPI
W32TimeSyncNow(LPCWSTR cmdline,
UINT blocking,
UINT flags)
{
DWORD result;
result = SetTime();
if (result)
{
DPRINT("W32TimeSyncNow failed and clock not set.\n");
}
else
{
DPRINT("W32TimeSyncNow succeeded and clock set.\n");
}
return result;
}
2 changes: 2 additions & 0 deletions base/services/w32time/w32time.h
Expand Up @@ -11,7 +11,9 @@
#include <winbase.h>
#include <winnls.h>
#include <winreg.h>
#include <winsvc.h>

#define MAX_VALUE_NAME 16383
#define NTPPORT 123


Expand Down
1 change: 1 addition & 0 deletions base/services/w32time/w32time.spec
@@ -1 +1,2 @@
18 stdcall W32TimeSyncNow(wstr long long)
21 stdcall ServiceMain(long ptr)
3 changes: 2 additions & 1 deletion boot/bootdata/hivesft.inf
Expand Up @@ -1520,6 +1520,7 @@ HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\wlballoon","L
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\wlballoon","Logon",0x00000000,"RegisterTicketExpiredNotificationEvent"

; Time Zone Servers
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers",,0x00000000,"1"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers","1",0x00000000,"pool.ntp.org"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers","2",0x00000000,"asia.pool.ntp.org"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers","3",0x00000000,"europe.pool.ntp.org"
Expand Down Expand Up @@ -1780,7 +1781,7 @@ HKLM,"SOFTWARE\Microsoft\Ole","EnableRemoteConnect",0x00000000,"N"
; SvcHost services
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","DcomLaunch",0x00010000,"DcomLaunch","PlugPlay"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","Themes","winmgmt"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","Themes","winmgmt","W32Time"

; Win32 config
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",,0x00000012
Expand Down

0 comments on commit e4898e6

Please sign in to comment.