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