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