[DHCPCSVC] Fix a memory leak in bind_lease introduced in r14645 (!). CORE-14353
[reactos.git] / base / services / dhcpcsvc / dhcpcsvc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/dhcpcapi/dhcpcapi.c
5 * PURPOSE: Client API for DHCP
6 * COPYRIGHT: Copyright 2005 Art Yerkes <ayerkes@speakeasy.net>
7 */
8
9 #include <rosdhcp.h>
10 #include <winsvc.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static WCHAR ServiceName[] = L"DHCP";
16
17 SERVICE_STATUS_HANDLE ServiceStatusHandle = 0;
18 SERVICE_STATUS ServiceStatus;
19
20 static HANDLE PipeHandle = INVALID_HANDLE_VALUE;
21
22 DWORD APIENTRY
23 DhcpCApiInitialize(LPDWORD Version)
24 {
25 DWORD PipeMode;
26
27 /* Wait for the pipe to be available */
28 if (!WaitNamedPipeW(DHCP_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT))
29 {
30 /* No good, we failed */
31 return GetLastError();
32 }
33
34 /* It's available, let's try to open it */
35 PipeHandle = CreateFileW(DHCP_PIPE_NAME,
36 GENERIC_READ | GENERIC_WRITE,
37 FILE_SHARE_READ | FILE_SHARE_WRITE,
38 NULL,
39 OPEN_EXISTING,
40 0,
41 NULL);
42
43 /* Check if we succeeded in opening the pipe */
44 if (PipeHandle == INVALID_HANDLE_VALUE)
45 {
46 /* We didn't */
47 return GetLastError();
48 }
49
50 /* Change the pipe into message mode */
51 PipeMode = PIPE_READMODE_MESSAGE;
52 if (!SetNamedPipeHandleState(PipeHandle, &PipeMode, NULL, NULL))
53 {
54 /* Mode change failed */
55 CloseHandle(PipeHandle);
56 PipeHandle = INVALID_HANDLE_VALUE;
57 return GetLastError();
58 }
59 else
60 {
61 /* We're good to go */
62 *Version = 2;
63 return NO_ERROR;
64 }
65 }
66
67 VOID APIENTRY
68 DhcpCApiCleanup(VOID)
69 {
70 CloseHandle(PipeHandle);
71 PipeHandle = INVALID_HANDLE_VALUE;
72 }
73
74 DWORD APIENTRY
75 DhcpQueryHWInfo(DWORD AdapterIndex,
76 PDWORD MediaType,
77 PDWORD Mtu,
78 PDWORD Speed)
79 {
80 COMM_DHCP_REQ Req;
81 COMM_DHCP_REPLY Reply;
82 DWORD BytesRead;
83 BOOL Result;
84
85 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
86
87 Req.Type = DhcpReqQueryHWInfo;
88 Req.AdapterIndex = AdapterIndex;
89
90 Result = TransactNamedPipe(PipeHandle,
91 &Req, sizeof(Req),
92 &Reply, sizeof(Reply),
93 &BytesRead, NULL);
94 if (!Result)
95 {
96 /* Pipe transaction failed */
97 return 0;
98 }
99
100 if (Reply.Reply == 0)
101 return 0;
102
103 *MediaType = Reply.QueryHWInfo.MediaType;
104 *Mtu = Reply.QueryHWInfo.Mtu;
105 *Speed = Reply.QueryHWInfo.Speed;
106 return 1;
107 }
108
109 DWORD APIENTRY
110 DhcpLeaseIpAddress(DWORD AdapterIndex)
111 {
112 COMM_DHCP_REQ Req;
113 COMM_DHCP_REPLY Reply;
114 DWORD BytesRead;
115 BOOL Result;
116
117 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
118
119 Req.Type = DhcpReqLeaseIpAddress;
120 Req.AdapterIndex = AdapterIndex;
121
122 Result = TransactNamedPipe(PipeHandle,
123 &Req, sizeof(Req),
124 &Reply, sizeof(Reply),
125 &BytesRead, NULL);
126 if (!Result)
127 {
128 /* Pipe transaction failed */
129 return 0;
130 }
131
132 return Reply.Reply;
133 }
134
135 DWORD APIENTRY
136 DhcpReleaseIpAddressLease(DWORD AdapterIndex)
137 {
138 COMM_DHCP_REQ Req;
139 COMM_DHCP_REPLY Reply;
140 DWORD BytesRead;
141 BOOL Result;
142
143 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
144
145 Req.Type = DhcpReqReleaseIpAddress;
146 Req.AdapterIndex = AdapterIndex;
147
148 Result = TransactNamedPipe(PipeHandle,
149 &Req, sizeof(Req),
150 &Reply, sizeof(Reply),
151 &BytesRead, NULL);
152 if (!Result)
153 {
154 /* Pipe transaction failed */
155 return 0;
156 }
157
158 return Reply.Reply;
159 }
160
161 DWORD APIENTRY
162 DhcpRenewIpAddressLease(DWORD AdapterIndex)
163 {
164 COMM_DHCP_REQ Req;
165 COMM_DHCP_REPLY Reply;
166 DWORD BytesRead;
167 BOOL Result;
168
169 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
170
171 Req.Type = DhcpReqRenewIpAddress;
172 Req.AdapterIndex = AdapterIndex;
173
174 Result = TransactNamedPipe(PipeHandle,
175 &Req, sizeof(Req),
176 &Reply, sizeof(Reply),
177 &BytesRead, NULL);
178 if (!Result)
179 {
180 /* Pipe transaction failed */
181 return 0;
182 }
183
184 return Reply.Reply;
185 }
186
187 DWORD APIENTRY
188 DhcpStaticRefreshParams(DWORD AdapterIndex,
189 DWORD Address,
190 DWORD Netmask)
191 {
192 COMM_DHCP_REQ Req;
193 COMM_DHCP_REPLY Reply;
194 DWORD BytesRead;
195 BOOL Result;
196
197 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
198
199 Req.Type = DhcpReqStaticRefreshParams;
200 Req.AdapterIndex = AdapterIndex;
201 Req.Body.StaticRefreshParams.IPAddress = Address;
202 Req.Body.StaticRefreshParams.Netmask = Netmask;
203
204 Result = TransactNamedPipe(PipeHandle,
205 &Req, sizeof(Req),
206 &Reply, sizeof(Reply),
207 &BytesRead, NULL);
208 if (!Result)
209 {
210 /* Pipe transaction failed */
211 return 0;
212 }
213
214 return Reply.Reply;
215 }
216
217 /*!
218 * Set new TCP/IP parameters and notify DHCP client service of this
219 *
220 * \param[in] ServerName
221 * NULL for local machine
222 *
223 * \param[in] AdapterName
224 * IPHLPAPI name of adapter to change
225 *
226 * \param[in] NewIpAddress
227 * TRUE if IP address changes
228 *
229 * \param[in] IpAddress
230 * New IP address (network byte order)
231 *
232 * \param[in] SubnetMask
233 * New subnet mask (network byte order)
234 *
235 * \param[in] DhcpAction
236 * 0 - don't modify
237 * 1 - enable DHCP
238 * 2 - disable DHCP
239 *
240 * \return non-zero on success
241 *
242 * \remarks Undocumented by Microsoft
243 */
244 DWORD APIENTRY
245 DhcpNotifyConfigChange(LPWSTR ServerName,
246 LPWSTR AdapterName,
247 BOOL NewIpAddress,
248 DWORD IpIndex,
249 DWORD IpAddress,
250 DWORD SubnetMask,
251 INT DhcpAction)
252 {
253 DPRINT1("DHCPCSVC: DhcpNotifyConfigChange not implemented yet\n");
254 return 0;
255 }
256
257 /*!
258 * Get DHCP info for an adapter
259 *
260 * \param[in] AdapterIndex
261 * Index of the adapter (iphlpapi-style) for which info is
262 * requested
263 *
264 * \param[out] DhcpEnabled
265 * Returns whether DHCP is enabled for the adapter
266 *
267 * \param[out] DhcpServer
268 * Returns DHCP server IP address (255.255.255.255 if no
269 * server reached yet), in network byte order
270 *
271 * \param[out] LeaseObtained
272 * Returns time at which the lease was obtained
273 *
274 * \param[out] LeaseExpires
275 * Returns time at which the lease will expire
276 *
277 * \return non-zero on success
278 *
279 * \remarks This is a ReactOS-only routine
280 */
281 DWORD APIENTRY
282 DhcpRosGetAdapterInfo(DWORD AdapterIndex,
283 PBOOL DhcpEnabled,
284 PDWORD DhcpServer,
285 time_t* LeaseObtained,
286 time_t* LeaseExpires)
287 {
288 COMM_DHCP_REQ Req;
289 COMM_DHCP_REPLY Reply;
290 DWORD BytesRead;
291 BOOL Result;
292
293 ASSERT(PipeHandle != INVALID_HANDLE_VALUE);
294
295 Req.Type = DhcpReqGetAdapterInfo;
296 Req.AdapterIndex = AdapterIndex;
297
298 Result = TransactNamedPipe(PipeHandle,
299 &Req, sizeof(Req),
300 &Reply, sizeof(Reply),
301 &BytesRead, NULL);
302
303 if (Result && Reply.Reply != 0)
304 *DhcpEnabled = Reply.GetAdapterInfo.DhcpEnabled;
305 else
306 *DhcpEnabled = FALSE;
307
308 if (*DhcpEnabled)
309 {
310 *DhcpServer = Reply.GetAdapterInfo.DhcpServer;
311 *LeaseObtained = Reply.GetAdapterInfo.LeaseObtained;
312 *LeaseExpires = Reply.GetAdapterInfo.LeaseExpires;
313 }
314 else
315 {
316 *DhcpServer = INADDR_NONE;
317 *LeaseObtained = 0;
318 *LeaseExpires = 0;
319 }
320
321 return Reply.Reply;
322 }
323
324
325 static VOID
326 UpdateServiceStatus(DWORD dwState)
327 {
328 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
329 ServiceStatus.dwCurrentState = dwState;
330
331 ServiceStatus.dwControlsAccepted = 0;
332
333 ServiceStatus.dwWin32ExitCode = 0;
334 ServiceStatus.dwServiceSpecificExitCode = 0;
335 ServiceStatus.dwCheckPoint = 0;
336
337 if (dwState == SERVICE_START_PENDING ||
338 dwState == SERVICE_STOP_PENDING ||
339 dwState == SERVICE_PAUSE_PENDING ||
340 dwState == SERVICE_CONTINUE_PENDING)
341 ServiceStatus.dwWaitHint = 10000;
342 else
343 ServiceStatus.dwWaitHint = 0;
344
345 SetServiceStatus(ServiceStatusHandle,
346 &ServiceStatus);
347 }
348
349 static DWORD WINAPI
350 ServiceControlHandler(DWORD dwControl,
351 DWORD dwEventType,
352 LPVOID lpEventData,
353 LPVOID lpContext)
354 {
355 switch (dwControl)
356 {
357 case SERVICE_CONTROL_STOP:
358 UpdateServiceStatus(SERVICE_STOP_PENDING);
359 UpdateServiceStatus(SERVICE_STOPPED);
360 return ERROR_SUCCESS;
361
362 case SERVICE_CONTROL_PAUSE:
363 UpdateServiceStatus(SERVICE_PAUSED);
364 return ERROR_SUCCESS;
365
366 case SERVICE_CONTROL_CONTINUE:
367 UpdateServiceStatus(SERVICE_START_PENDING);
368 UpdateServiceStatus(SERVICE_RUNNING);
369 return ERROR_SUCCESS;
370
371 case SERVICE_CONTROL_INTERROGATE:
372 SetServiceStatus(ServiceStatusHandle,
373 &ServiceStatus);
374 return ERROR_SUCCESS;
375
376 case SERVICE_CONTROL_SHUTDOWN:
377 UpdateServiceStatus(SERVICE_STOP_PENDING);
378 UpdateServiceStatus(SERVICE_STOPPED);
379 return ERROR_SUCCESS;
380
381 default :
382 return ERROR_CALL_NOT_IMPLEMENTED;
383 }
384 }
385
386 VOID WINAPI
387 ServiceMain(DWORD argc, LPWSTR* argv)
388 {
389 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
390 ServiceControlHandler,
391 NULL);
392 if (!ServiceStatusHandle)
393 {
394 DPRINT1("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
395 return;
396 }
397
398 UpdateServiceStatus(SERVICE_START_PENDING);
399
400 if (!init_client())
401 {
402 DPRINT1("DHCPCSVC: init_client() failed!\n");
403 UpdateServiceStatus(SERVICE_STOPPED);
404 return;
405 }
406
407 DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
408
409 UpdateServiceStatus(SERVICE_RUNNING);
410
411 DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
412 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n"));
413
414 dispatch();
415
416 DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n"));
417 stop_client();
418
419 UpdateServiceStatus(SERVICE_STOPPED);
420 }
421
422 BOOL WINAPI
423 DllMain(HINSTANCE hinstDLL,
424 DWORD fdwReason,
425 LPVOID lpvReserved)
426 {
427 switch (fdwReason)
428 {
429 case DLL_PROCESS_ATTACH:
430 DisableThreadLibraryCalls(hinstDLL);
431 break;
432
433 case DLL_PROCESS_DETACH:
434 break;
435 }
436
437 return TRUE;
438 }
439
440 /* EOF */