a8aed3f4d157db3e17ef7f689e187cc813231e1e
[reactos.git] / dll / cpl / timedate / w32time.c
1 /*
2 * PROJECT: ReactOS Timedate Control Panel
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Create W32Time Service that reqularly syncs clock to Internet Time
5 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
6 */
7
8 #include "timedate.h"
9
10 /* Get the domain name from the registry */
11 static BOOL
12 GetNTPServerAddress(LPWSTR *lpAddress)
13 {
14 HKEY hKey;
15 WCHAR szSel[4];
16 DWORD dwSize;
17 LONG lRet;
18
19 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
20 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\DateTime\\Servers",
21 0,
22 KEY_QUERY_VALUE,
23 &hKey);
24 if (lRet != ERROR_SUCCESS)
25 goto fail;
26
27 /* Get data from default value */
28 dwSize = 4 * sizeof(WCHAR);
29 lRet = RegQueryValueExW(hKey,
30 NULL,
31 NULL,
32 NULL,
33 (LPBYTE)szSel,
34 &dwSize);
35 if (lRet != ERROR_SUCCESS)
36 goto fail;
37
38 dwSize = 0;
39 lRet = RegQueryValueExW(hKey,
40 szSel,
41 NULL,
42 NULL,
43 NULL,
44 &dwSize);
45 if (lRet != ERROR_SUCCESS)
46 goto fail;
47
48 (*lpAddress) = (LPWSTR)HeapAlloc(GetProcessHeap(),
49 0,
50 dwSize);
51 if ((*lpAddress) == NULL)
52 {
53 lRet = ERROR_NOT_ENOUGH_MEMORY;
54 goto fail;
55 }
56
57 lRet = RegQueryValueExW(hKey,
58 szSel,
59 NULL,
60 NULL,
61 (LPBYTE)*lpAddress,
62 &dwSize);
63 if (lRet != ERROR_SUCCESS)
64 goto fail;
65
66 RegCloseKey(hKey);
67
68 return TRUE;
69
70 fail:
71 DisplayWin32Error(lRet);
72 if (hKey)
73 RegCloseKey(hKey);
74 HeapFree(GetProcessHeap(), 0, *lpAddress);
75 return FALSE;
76 }
77
78
79 /* Request the time from the current NTP server */
80 static ULONG
81 GetTimeFromServer(VOID)
82 {
83 LPWSTR lpAddress = NULL;
84 ULONG ulTime = 0;
85
86 if (GetNTPServerAddress(&lpAddress))
87 {
88 ulTime = GetServerTime(lpAddress);
89
90 HeapFree(GetProcessHeap(),
91 0,
92 lpAddress);
93 }
94
95 return ulTime;
96 }
97
98
99 BOOL
100 SystemSetTime(LPSYSTEMTIME lpSystemTime)
101 {
102 HANDLE hToken;
103 DWORD PrevSize;
104 TOKEN_PRIVILEGES priv, previouspriv;
105 BOOL Ret = FALSE;
106
107 /*
108 * Enable the SeSystemtimePrivilege privilege
109 */
110
111 if (OpenProcessToken(GetCurrentProcess(),
112 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
113 &hToken))
114 {
115 priv.PrivilegeCount = 1;
116 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
117
118 if (LookupPrivilegeValueW(NULL,
119 SE_SYSTEMTIME_NAME,
120 &priv.Privileges[0].Luid))
121 {
122 if (AdjustTokenPrivileges(hToken,
123 FALSE,
124 &priv,
125 sizeof(previouspriv),
126 &previouspriv,
127 &PrevSize) &&
128 GetLastError() == ERROR_SUCCESS)
129 {
130 /*
131 * We successfully enabled it, we're permitted to change the time.
132 */
133 Ret = SetSystemTime(lpSystemTime);
134
135 /*
136 * For the sake of security, restore the previous status again
137 */
138 if (previouspriv.PrivilegeCount > 0)
139 {
140 AdjustTokenPrivileges(hToken,
141 FALSE,
142 &previouspriv,
143 0,
144 NULL,
145 0);
146 }
147 }
148 }
149 CloseHandle(hToken);
150 }
151
152 return Ret;
153 }
154
155
156 /*
157 * NTP servers state the number of seconds passed since
158 * 1st Jan, 1900. The time returned from the server
159 * needs adding to that date to get the current Gregorian time
160 */
161 static VOID
162 UpdateSystemTime(ULONG ulTime)
163 {
164 FILETIME ftNew;
165 LARGE_INTEGER li;
166 SYSTEMTIME stNew;
167
168 /* Time at 1st Jan 1900 */
169 stNew.wYear = 1900;
170 stNew.wMonth = 1;
171 stNew.wDay = 1;
172 stNew.wHour = 0;
173 stNew.wMinute = 0;
174 stNew.wSecond = 0;
175 stNew.wMilliseconds = 0;
176
177 /* Convert to a file time */
178 if (!SystemTimeToFileTime(&stNew, &ftNew))
179 {
180 DisplayWin32Error(GetLastError());
181 return;
182 }
183
184 /* Add on the time passed since 1st Jan 1900 */
185 li = *(LARGE_INTEGER *)&ftNew;
186 li.QuadPart += (LONGLONG)10000000 * ulTime;
187 ftNew = * (FILETIME *)&li;
188
189 /* Convert back to a system time */
190 if (!FileTimeToSystemTime(&ftNew, &stNew))
191 {
192 DisplayWin32Error(GetLastError());
193 return;
194 }
195
196 if (!SystemSetTime(&stNew))
197 {
198 DisplayWin32Error(GetLastError());
199 }
200 }
201
202
203 VOID
204 SyncTimeNow(VOID)
205 {
206 ULONG ulTime;
207 ulTime = GetTimeFromServer();
208 if (ulTime != 0)
209 UpdateSystemTime(ulTime);
210 }
211