windows-free-lib-20050418
[openafs.git] / src / WINNT / afsreg / syscfg.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* Functions for accessing NT system configuration information. */
11
12 #include <windows.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <winsock2.h>
16 #include <iphlpapi.h>
17 #include <iptypes.h>
18 #include <ipifcons.h>
19
20 #include "afsreg.h"
21 #include "syscfg.h"
22
23 static int IsLoopback(char * guid);
24
25 /* syscfg_GetIFInfo
26  *
27  * Retrieve IP addresses, subnet masks, MTU sizes, and flags for all
28  * configured interfaces.
29  *
30  * Arguments:
31  * IN/OUT:
32  *      count - in is max size of arrays. out is number of elements used.
33  *
34  * OUT:
35  *      addrs - array of configured IP addresses, in host order.
36  *      masks - array of subnet masks, in host order.
37  *      mtus  - array of MTU sizes.
38  *      flags - array of flags.
39  *
40  * Return Value:
41  *      Total number of configured interfaces (>= count) or -1 on error.
42  */
43
44 int syscfg_GetIFInfo(int *count, int *addrs, int *masks, int *mtus, int *flags)
45 {
46     PMIB_IPADDRTABLE pIpAddrTable = NULL;
47     ULONG            dwSize;
48     DWORD            code;
49     DWORD            index;
50     DWORD            validAddrs = 0;
51
52     int maxCount = *count;
53     int nConfig = 0;
54     PIP_ADAPTER_ADDRESSES pAddresses, cAddress;
55     PMIB_IPADDRTABLE pIpTbl;
56     ULONG outBufLen = 0;
57     DWORD dwRetVal = 0;
58     int n = 0;
59     DWORD i;
60
61     HMODULE hIpHlp;
62     DWORD (WINAPI *pGetAdaptersAddresses)(ULONG, DWORD, PVOID, 
63                                           PIP_ADAPTER_ADDRESSES, PULONG) = 0;
64
65     hIpHlp = LoadLibrary("iphlpapi");
66     if (hIpHlp != NULL) {
67         (FARPROC) pGetAdaptersAddresses = GetProcAddress(hIpHlp, "GetAdaptersAddresses");
68         if (pGetAdaptersAddresses == NULL)
69             FreeLibrary(hIpHlp);
70     }
71
72     if (pGetAdaptersAddresses == NULL)
73         return syscfg_GetIFInfo_2000(count, addrs, masks, mtus, flags);
74
75     /* first pass to get the required size of the IP table */
76     pIpTbl = (PMIB_IPADDRTABLE) malloc(sizeof(MIB_IPADDRTABLE));
77     outBufLen = sizeof(MIB_IPADDRTABLE);
78     
79     dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
80     if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
81         /* this should have failed with an insufficient buffer because we
82            didn't give any space to place the IP addresses */
83         free(pIpTbl);
84         *count = 0;
85         nConfig = -1;
86         goto done;
87     }
88     
89     /* second pass to get the actual data */
90     free(pIpTbl);
91     pIpTbl = (PMIB_IPADDRTABLE) malloc(outBufLen);
92     
93     dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
94     if (dwRetVal != NO_ERROR) {
95         free(pIpTbl);
96         *count = 0;
97         nConfig = -1;
98         goto done;
99     }
100     
101     pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(sizeof(IP_ADAPTER_ADDRESSES));
102     
103     /* first call gets required buffer size */
104     if (pGetAdaptersAddresses(AF_INET, 
105                               0, 
106                               NULL, 
107                               pAddresses, 
108                               &outBufLen) == ERROR_BUFFER_OVERFLOW) 
109     {
110         free(pAddresses);
111         pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen);
112     } else {
113         free(pIpTbl);
114         *count = 0;
115         nConfig = -1;
116         goto done;
117     }
118     
119     /* second call to get the actual data */
120     if ((dwRetVal = pGetAdaptersAddresses(AF_INET, 
121                                           0, 
122                                           NULL, 
123                                           pAddresses, 
124                                           &outBufLen)) == NO_ERROR) 
125     {
126         /* we have a list of addresses.  go through them and figure out
127            the IP addresses */
128         for (cAddress = pAddresses; cAddress; cAddress = cAddress->Next) {
129             
130             /* skip software loopback adapters */
131             if (cAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
132                 continue;
133             
134             /* also skip interfaces that are not up */
135             if (cAddress->OperStatus != 1)
136                 continue;
137             
138             /* starting with the AdapterName, which is actually the adapter
139                instance GUID, check if this is a MS loopback device */
140             if (IsLoopback(cAddress->AdapterName))
141                 continue;
142             
143             /* ok. looks good.  Now fish out all the addresses from the
144                address table corresponding to the interface, and add them
145                to the list */
146             for (i=0;i<pIpTbl->dwNumEntries;i++) {
147                 if (pIpTbl->table[i].dwIndex == cAddress->IfIndex)
148                 {
149                     if (n < maxCount) {
150                         addrs[n] = ntohl(pIpTbl->table[i].dwAddr);
151                         masks[n] = ntohl(pIpTbl->table[i].dwMask);
152                         mtus[n] = cAddress->Mtu;
153                         flags[n] = 0;
154                         n++;
155                     }
156                     nConfig++;
157                 }
158             }
159         }
160         
161         free(pAddresses);
162         free(pIpTbl);
163         
164         *count = n;
165     } else { 
166         /* again. this is bad */
167         free(pAddresses);
168         free(pIpTbl);
169         *count = 0;
170         nConfig = -1;
171     }
172
173   done:
174     FreeLibrary(hIpHlp);
175     return nConfig;
176 }
177
178 static int IsLoopback(char * guid)
179 {
180     int isloopback = FALSE;
181  
182     HKEY hkNet = NULL;
183     HKEY hkDev = NULL;
184     HKEY hkDevConn = NULL;
185     HKEY hkEnum = NULL;
186     HKEY hkAdapter = NULL;
187     
188     char pnpIns[MAX_PATH];
189     char hwId[MAX_PATH];
190     char service[MAX_PATH];
191     
192     DWORD size;
193     
194     /* Open the network adapters key */
195     if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hkNet)))
196         goto _exit;
197     
198     /* open the guid key */
199     if (FAILED(RegOpenKeyEx(hkNet, guid, 0, KEY_READ, &hkDev)))
200         goto _exit;
201     
202     /* then the connection */
203     if (FAILED(RegOpenKeyEx(hkDev, "Connection", 0, KEY_READ, &hkDevConn)))
204         goto _exit;
205     
206     /* and find out the plug-n-play instance ID */
207     size = MAX_PATH;
208     if (FAILED(RegQueryValueEx(hkDevConn, "PnpInstanceID", NULL, NULL, pnpIns, &size)))
209         goto _exit;
210     
211     /* now look in the device ENUM */
212     if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum", 0, KEY_READ, &hkEnum)))
213         goto _exit;
214     
215     /* for the instance that we found above */
216     if (FAILED(RegOpenKeyEx(hkEnum, pnpIns, 0, KEY_READ, &hkAdapter)))
217         goto _exit;
218     
219     /* and fetch the harware ID */
220     size = MAX_PATH;
221     if (FAILED(RegQueryValueEx(hkAdapter, "HardwareID", NULL, NULL, hwId, &size)))
222         goto _exit;
223     
224     size = MAX_PATH;
225     if (FAILED(RegQueryValueEx(hkAdapter, "Service", NULL, NULL, service, &size)))
226         goto _exit;
227     
228     /* and see if it is the loopback adapter */
229     if (!stricmp(hwId, "*msloop") || !stricmp(service, "msloop"))
230         isloopback = TRUE;
231     
232   _exit:
233     if (hkAdapter)
234         RegCloseKey(hkAdapter);
235     if (hkEnum)
236         RegCloseKey(hkEnum);
237     if (hkDevConn)
238         RegCloseKey(hkDevConn);
239     if (hkDev)
240         RegCloseKey(hkDev);
241     if (hkNet)
242         RegCloseKey(hkNet);
243  
244     return isloopback;
245 }
246
247 static int GetInterfaceList(HKEY skey, char **list);
248 static char *GetNextInterface(char *iflist);
249 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask);
250
251 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags)
252 {
253     int maxCount = *count;
254     char *IFListBase = NULL;
255     char *IFList, *ifname;
256     HKEY skey;
257     int i, n, nConfig;
258
259     if (RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_IPSRV_KEY,
260                       KEY_READ, 0, &skey, NULL))
261         return -1;
262
263     if ((nConfig = GetInterfaceList(skey, &IFListBase)) < 0) {
264         (void) RegCloseKey(skey);
265         return -1;
266     }
267
268     IFList = IFListBase;
269     n = 0;
270
271     while ((n < maxCount) && (ifname = GetNextInterface(IFList))) {
272         if (!IsLoopback(ifname) && GetIP(skey, ifname, &addrs[n], &masks[n]) == 0 && addrs[n] != 0) {
273             n++;
274         } else {
275             maxCount--;
276         }
277         IFList = ifname;
278     }
279
280     /* And until we get mtu's and flags */
281     for (i = 0; i < n; i++) {
282         mtus[i] = 1500;
283         flags[i] = 0;
284     }
285
286     (void) RegCloseKey(skey);
287     free(IFListBase);
288
289     *count = n;
290     return nConfig;
291 }
292
293
294 /* GetInterfaceList
295  *
296  * Get interface list; list is represented as a multistring.
297  * Returns number of elements in interface list or -1 on error.
298  */
299 static int GetInterfaceList(HKEY skey, char **list)
300 {
301     HKEY key;
302     long status;
303     char *str = NULL;
304     int size;
305     DWORD valType;
306
307     if (RegOpenKeyAlt(skey, AFSREG_IPSRV_IFACELIST_SUBKEY,
308                       KEY_READ, 0, &key, NULL))
309         return -1;
310
311     status = RegQueryValueAlt(key, AFSREG_IPSRV_IFACELIST_BIND_VALUE,
312                               &valType, &str, NULL);
313     (void) RegCloseKey(key);
314     if (status || (valType != REG_MULTI_SZ))
315         return -1;
316
317     /* Count strings in multistring. */
318     size = 0;
319
320     if (*str != '\0') {
321         int i;
322
323         for (i = 1; ; i++) {
324             if (str[i] == '\0') {
325                 /* hit end of string */
326                 size++;
327                 i++;
328                 if (str[i] == '\0') {
329                     /* hit end of multistring */
330                     break;
331                 }
332             }
333         }
334     }
335     *list = str;
336     return size;
337 }
338
339
340 /* GetNextInterface
341  *
342  * Parse interface list.  In first call to GetNextInterface(), iflist is
343  * the list returned by GetInterfaceList(); in successive calls, iflist is
344  * the pointer returned by the previous call to GetNextInterface().
345  *
346  * Returns pointer to next adapter name, or NULL if done.
347  */
348
349 static char *GetNextInterface(char *iflist)
350 {
351     char *ifname;
352
353     /* interface substrings are assumed to be of form \Device\<adapter name> 
354      * \Tcpip\Parameters\Interfaces\<adapter name>
355      */
356     ifname = strrchr(iflist, '\\');
357
358     if (!ifname) {
359         /* subsequent (not first) call; advance to next interface substring */
360         iflist += strlen(iflist) + 1;
361         /* iflist now points to next interface or end-of-multistring char */
362         ifname = strrchr(iflist, '\\');
363     }
364
365     if (ifname) {
366         /* advance to first character of adapter name */
367         ifname++;
368     }
369
370     return ifname;
371 }
372
373
374 /* GetIP
375  *
376  * Get IP address associated with interface (adapter name).
377  * Returns 0 on success and -1 on error.
378  */
379
380 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask)
381 {
382     HKEY key;
383     char *s;
384     long status;
385     int len;
386     char *ipStr = NULL;
387     char *snMask = NULL;
388     DWORD valType;
389     DWORD dwDHCP;
390     DWORD dwLease;
391     DWORD dwSize;
392
393     len = strlen(ifname) + 1 + sizeof(AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
394     s = malloc(len);
395     if (!s)
396         return -1;
397
398     sprintf(s, "%s\\%s", ifname, AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
399
400     status = RegOpenKeyAlt(skey, s, KEY_READ, 0, &key, NULL);
401     free(s);
402
403     if (status)
404         return -1;
405
406     dwSize = sizeof(DWORD);
407     status = RegQueryValueEx(key, "EnableDHCP", NULL,
408                              &valType, &dwDHCP, &dwSize);
409     if (status || (valType != REG_DWORD))
410         dwDHCP = 0;
411
412     if (dwDHCP == 0) {
413         status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_ADDR_VALUE,
414                                   &valType, &ipStr, NULL);
415         if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
416             if (ipStr) free(ipStr);
417             (void) RegCloseKey(key);
418             return -1;
419         }
420
421         status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_MASK_VALUE,
422                                   &valType, &snMask, NULL);
423         if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
424             if (snMask) free(snMask);
425             snMask = NULL;
426         }
427     } else {
428         /* adapter configured via DHCP; address/mask in alternate values */
429         dwSize = sizeof(DWORD);
430         status = RegQueryValueEx(key, "Lease", NULL,
431                                  &valType, &dwLease, &dwSize);
432         if (status || (valType != REG_DWORD) || dwLease == 0) {
433             (void) RegCloseKey(key);
434             return -1;
435         }
436
437         status = RegQueryValueAlt(key,
438                                   AFSREG_IPSRV_ADAPTER_PARAM_DHCPADDR_VALUE,
439                                   &valType, &ipStr, NULL);
440
441         if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
442             if (ipStr) free(ipStr);
443             (void) RegCloseKey(key);
444             return -1;
445         }
446
447         status = RegQueryValueAlt(key,
448                                   AFSREG_IPSRV_ADAPTER_PARAM_DHCPMASK_VALUE,
449                                   &valType, &snMask, NULL);
450
451         if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
452             if (snMask) free(snMask);
453             snMask = NULL;
454         }
455     }
456
457     /* convert ip and subnet. */
458     *addr = (int)inet_addr(ipStr);
459     *addr = ntohl(*addr);
460     free(ipStr);
461
462     if (snMask) {
463         *mask = (int)inet_addr(snMask);
464         *mask = ntohl(*mask);
465         free(snMask);
466     } else {
467         *mask = 0;
468     }
469
470     (void) RegCloseKey(key);
471
472     return 0;
473 }
474