1 /*
2  * iphlpapi dll implementation -- Setting and storing route information
3  *
4  * These are stubs for functions that set routing information on the target
5  * operating system.  They are grouped here because their implementation will
6  * vary widely by operating system.
7  *
8  * Copyright (C) 2004 Art Yerkes
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 #include <config.h>
25 #include "iphlpapi_private.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
28 
29 typedef struct _NAME_SERVER_LIST_PRIVATE {
30     UINT NumServers;
31     IP_ADDR_STRING * pCurrent;
32 } NAME_SERVER_LIST_PRIVATE, *PNAME_SERVER_LIST_PRIVATE;
33 
34 typedef VOID (*ENUM_INTERFACE_CALLBACK)(
35     HKEY ChildKeyHandle,
36     LPWSTR ChildKeyName,
37     PVOID CallbackContext);
38 
39 LSTATUS
QueryNameServer(IN HKEY hInterface,IN LPCWSTR NameServerKey,OUT LPWSTR * OutNameServer)40 QueryNameServer(
41     IN HKEY hInterface,
42     IN LPCWSTR NameServerKey,
43     OUT LPWSTR * OutNameServer)
44 {
45     DWORD dwLength, dwType;
46     LPWSTR NameServer;
47     LSTATUS Status;
48 
49     /* query ns */
50     dwLength = 0;
51     Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, NULL, &dwLength);
52 
53     if (Status != ERROR_SUCCESS)
54     {
55         /* failed to retrieve size */
56         TRACE("Status %x\n", Status);
57         return Status;
58     }
59 
60     /* add terminating null */
61     dwLength += sizeof(WCHAR);
62 
63     /* allocate name server */
64     NameServer = HeapAlloc(GetProcessHeap(), 0, dwLength);
65 
66     if (!NameServer)
67     {
68         /* no memory */
69         return ERROR_OUTOFMEMORY;
70     }
71 
72     /* query ns */
73     Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, (LPBYTE)NameServer, &dwLength);
74 
75     if (Status != ERROR_SUCCESS || dwType != REG_SZ)
76     {
77         /* failed to retrieve ns */
78         HeapFree(GetProcessHeap(), 0, NameServer);
79         return Status;
80     }
81 
82     /* null terminate it */
83     NameServer[dwLength / sizeof(WCHAR)] = L'\0';
84 
85     /* store result */
86     *OutNameServer = NameServer;
87 
88     return STATUS_SUCCESS;
89 }
90 
91 
92 LSTATUS
EnumNameServers(IN HKEY hInterface,IN LPWSTR InterfaceName,PVOID ServerCallbackContext,EnumNameServersFunc CallbackRoutine)93 EnumNameServers(
94     IN HKEY hInterface,
95     IN LPWSTR InterfaceName,
96     PVOID ServerCallbackContext,
97     EnumNameServersFunc CallbackRoutine)
98 {
99     LSTATUS Status;
100     LPWSTR NameServer;
101     WCHAR Buffer[50];
102     DWORD Length;
103     LPWSTR Start, Comma;
104 
105     /* query static assigned name server */
106     Status = QueryNameServer(hInterface, L"NameServer", &NameServer);
107     if (Status != ERROR_SUCCESS)
108     {
109         /* query dynamic assigned name server */
110         Status = QueryNameServer(hInterface, L"DhcpNameServer", &NameServer);
111 
112         if (Status != ERROR_SUCCESS)
113         {
114             /* failed to retrieve name servers */
115             return Status;
116         }
117     }
118 
119     /* enumerate all name servers, terminated by comma */
120     Start = NameServer;
121 
122     do
123     {
124         /* find next terminator */
125         Comma = wcschr(Start, L',');
126 
127         if (Comma)
128         {
129             /* calculate length */
130             Length = Comma - Start;
131 
132             /* copy name server */
133             RtlMoveMemory(Buffer, Start, Length * sizeof(WCHAR));
134 
135             /* null terminate it */
136             Buffer[Length] = L'\0';
137 
138             /* perform callback */
139             CallbackRoutine(InterfaceName, Buffer, ServerCallbackContext);
140 
141         }
142         else
143         {
144             /* perform callback */
145             CallbackRoutine(InterfaceName, Start, ServerCallbackContext);
146 
147             /* last entry */
148             break;
149         }
150 
151         /* increment offset */
152         Start = Comma + 1;
153 
154     }while(TRUE);
155 
156     /* free name server string */
157     HeapFree(GetProcessHeap(), 0, NameServer);
158 
159     /* done */
160     return ERROR_SUCCESS;
161 }
162 
163 LSTATUS
EnumInterfaces(ENUM_INTERFACE_CALLBACK CallbackRoutine,PVOID InterfaceCallbackContext)164 EnumInterfaces(
165     ENUM_INTERFACE_CALLBACK CallbackRoutine,
166     PVOID InterfaceCallbackContext)
167 {
168     HKEY hKey, hInterface;
169     LSTATUS Status;
170     DWORD NumInterfaces, InterfaceNameLen, Index, Length;
171     LPWSTR InterfaceName;
172 
173     /* first open interface key */
174     Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &hKey);
175 
176     /* check for success */
177     if (Status != ERROR_SUCCESS)
178     {
179         /* failed to open interface key */
180         return Status;
181     }
182 
183     /* now get maximum interface name length and number of interfaces */
184     Status = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &NumInterfaces, &InterfaceNameLen, NULL, NULL, NULL, NULL, NULL, NULL);
185     if (Status != ERROR_SUCCESS)
186     {
187         /* failed to get key info */
188         RegCloseKey(hKey);
189         return Status;
190     }
191 
192     /* RegQueryInfoKey does not include terminating null */
193     InterfaceNameLen++;
194 
195     /* allocate interface name */
196     InterfaceName = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, InterfaceNameLen * sizeof(WCHAR));
197 
198     if (!InterfaceName)
199     {
200         /* no memory */
201         RegCloseKey(hKey);
202         return ERROR_OUTOFMEMORY;
203     }
204 
205     /* no enumerate all interfaces */
206     for(Index = 0; Index < NumInterfaces; Index++)
207     {
208         /* query interface name */
209         Length = InterfaceNameLen;
210         Status = RegEnumKeyExW(hKey, Index, InterfaceName, &Length, NULL, NULL, NULL, NULL);
211 
212         if (Status == ERROR_SUCCESS)
213         {
214             /* make sure it is null terminated */
215             InterfaceName[Length] = L'\0';
216 
217             /* now open child key */
218             Status = RegOpenKeyExW(hKey, InterfaceName, 0, KEY_READ, &hInterface);
219 
220             if (Status == ERROR_SUCCESS)
221             {
222                 /* perform enumeration callback */
223                 CallbackRoutine(hInterface, InterfaceName, InterfaceCallbackContext);
224 
225                 /* close interface key */
226                 RegCloseKey(hInterface);
227             }
228         }
229     }
230 
231     /* free interface name */
232     HeapFree(GetProcessHeap(), 0, InterfaceName);
233 
234     /* close root interface key */
235     RegCloseKey(hKey);
236 
237     /* done */
238     return Status;
239 }
240 
241 VOID
CountNameServerCallback(IN LPWSTR InterfaceName,IN LPWSTR Server,IN PVOID CallbackContext)242 CountNameServerCallback(
243     IN LPWSTR InterfaceName,
244     IN LPWSTR Server,
245     IN PVOID CallbackContext)
246 {
247     /* get context */
248     PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext;
249 
250     /* increment server count */
251     Data->NumServers++;
252 }
253 
254 VOID
CountServerCallbackTrampoline(HKEY ChildKeyHandle,LPWSTR ChildKeyName,PVOID CallbackContext)255 CountServerCallbackTrampoline(
256     HKEY ChildKeyHandle,
257     LPWSTR ChildKeyName,
258     PVOID CallbackContext)
259 {
260     EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CountNameServerCallback);
261 }
262 
263 LSTATUS
CountNameServers(IN PNAME_SERVER_LIST_PRIVATE PrivateData)264 CountNameServers(
265     IN PNAME_SERVER_LIST_PRIVATE PrivateData )
266 {
267     return EnumInterfaces(CountServerCallbackTrampoline, (PVOID)PrivateData);
268 }
269 
270 VOID
CreateNameServerListCallback(IN LPWSTR InterfaceName,IN LPWSTR Server,IN PVOID CallbackContext)271 CreateNameServerListCallback(
272     IN LPWSTR InterfaceName,
273     IN LPWSTR Server,
274     IN PVOID CallbackContext)
275 {
276     /* get context */
277     PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext;
278 
279     /* convert to ansi ns string */
280     if (WideCharToMultiByte(CP_ACP, 0, Server, -1, Data->pCurrent->IpAddress.String, 16, NULL, NULL))
281     {
282         /* store offset to next name server struct */
283         Data->pCurrent->Next = (struct _IP_ADDR_STRING*)(Data->pCurrent + 1);
284 
285         /* move to next entry */
286         Data->pCurrent = Data->pCurrent->Next;
287 
288         /* increment server count */
289         Data->NumServers++;
290     }
291     else
292     {
293         /* failed to convert dns server */
294         Data->pCurrent->IpAddress.String[0] = '\0';
295     }
296 }
297 
298 VOID
CreateNameServerListCallbackTrampoline(HKEY ChildKeyHandle,LPWSTR ChildKeyName,PVOID CallbackContext)299 CreateNameServerListCallbackTrampoline(
300     HKEY ChildKeyHandle,
301     LPWSTR ChildKeyName,
302     PVOID CallbackContext)
303 {
304     EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CreateNameServerListCallback);
305 }
306 
307 LSTATUS
MakeNameServerList(PNAME_SERVER_LIST_PRIVATE PrivateData)308 MakeNameServerList(
309     PNAME_SERVER_LIST_PRIVATE PrivateData )
310 {
311     return EnumInterfaces(CreateNameServerListCallbackTrampoline, (PVOID)PrivateData);
312 }
313 
314 PIPHLP_RES_INFO
getResInfo()315 getResInfo()
316 {
317     NAME_SERVER_LIST_PRIVATE PrivateNSEnum;
318     PIPHLP_RES_INFO ResInfo;
319     IP_ADDR_STRING * DnsList = NULL;
320     LSTATUS Status;
321 
322     PrivateNSEnum.NumServers = 0;
323 
324     /* count name servers */
325     Status = CountNameServers(&PrivateNSEnum);
326 
327     if (Status != ERROR_SUCCESS)
328     {
329         /* failed to enumerate name servers */
330         return NULL;
331     }
332 
333     /* are there any servers */
334     if (PrivateNSEnum.NumServers)
335     {
336         /* allocate dns servers */
337         DnsList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PrivateNSEnum.NumServers * sizeof(IP_ADDR_STRING));
338 
339         if (!DnsList)
340         {
341             /* no memory */
342             return NULL;
343         }
344     }
345 
346     /* allocate private struct */
347     ResInfo = (PIPHLP_RES_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IPHLP_RES_INFO));
348 
349     if(!ResInfo)
350     {
351         /* no memory */
352         if (DnsList)
353         {
354             /* free dns list */
355             HeapFree( GetProcessHeap(), 0, DnsList);
356         }
357         return NULL;
358     }
359 
360     /* are there any servers */
361     if (PrivateNSEnum.NumServers)
362     {
363         /* initialize enumeration context */
364         PrivateNSEnum.NumServers = 0;
365         PrivateNSEnum.pCurrent = DnsList;
366 
367         /* enumerate servers */
368         MakeNameServerList( &PrivateNSEnum );
369 
370         /* store result */
371         ResInfo->DnsList = DnsList;
372         ResInfo->riCount = PrivateNSEnum.NumServers;
373     }
374 
375     /* done */
376     return ResInfo;
377 }
378 
disposeResInfo(PIPHLP_RES_INFO InfoPtr)379 VOID disposeResInfo( PIPHLP_RES_INFO InfoPtr )
380 {
381     HeapFree(GetProcessHeap(), 0, InfoPtr->DnsList);
382     RtlFreeHeap( GetProcessHeap(), 0, InfoPtr );
383 }
384