Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afsreg / syscfg.c
blobed278b6f2360096ff2a8cf8e1c879cb59ae994d5
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
10 /* Functions for accessing NT system configuration information. */
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>
20 #include "afsreg.h"
21 #include "syscfg.h"
23 #ifdef DEBUG
24 #include <strsafe.h>
25 #endif
27 static int IsLoopback(char * guid);
28 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags);
30 DWORD GetMTUForAddress(PIP_ADAPTER_ADDRESSES cAddress)
32 DWORD min_mtu = 0xFFFFFFFF; /* Default */
34 HKEY hk_services = NULL;
36 HKEY hk_adapters = NULL;
38 HKEY hk_adapter = NULL;
40 char * ipconfig = NULL;
42 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", 0,
43 KEY_READ, &hk_services) != ERROR_SUCCESS)
44 goto done;
46 if (RegOpenKeyEx(hk_services, "Tcpip\\Parameters\\Adapters", 0, KEY_READ,
47 &hk_adapters)
48 != ERROR_SUCCESS)
49 goto done;
51 if (RegOpenKeyEx(hk_adapters, cAddress->AdapterName, 0, KEY_READ, &hk_adapter)
52 != ERROR_SUCCESS)
53 goto done;
56 DWORD cb_alloc = 0;
57 DWORD cb_ipc = 0;
58 DWORD type = 0;
59 char * this_ipc;
61 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, NULL, NULL, &cb_ipc)
62 != ERROR_SUCCESS)
63 goto done;
65 cb_alloc = cb_ipc + sizeof(char) * 2;
66 ipconfig = malloc(cb_alloc);
67 if (ipconfig == NULL)
68 goto done;
70 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, &type, ipconfig,
71 &cb_ipc) != ERROR_SUCCESS) {
72 goto done;
75 if (cb_ipc < cb_alloc)
76 memset(ipconfig + cb_ipc / sizeof(char), 0,
77 (cb_alloc - cb_ipc) / sizeof(char));
79 for (this_ipc = ipconfig; (this_ipc - ipconfig) < cb_alloc / sizeof(char) &&
80 *this_ipc; this_ipc = this_ipc + (strlen(this_ipc) + 1)) {
82 HKEY hk_interface = NULL;
83 DWORD mtu = 0;
84 DWORD cb_mtu;
86 if (RegOpenKeyEx(hk_services, this_ipc, 0, KEY_READ,
87 &hk_interface) != ERROR_SUCCESS)
88 continue;
90 cb_mtu = sizeof(mtu);
91 if (RegQueryValueEx(hk_interface, "MTU", NULL, NULL, &mtu,
92 &cb_mtu) == ERROR_SUCCESS) {
93 min_mtu = min(min_mtu, mtu);
96 RegCloseKey(hk_interface);
100 done:
101 if (ipconfig)
102 free(ipconfig);
104 if (hk_services != NULL)
105 RegCloseKey(hk_services);
107 if (hk_adapters != NULL)
108 RegCloseKey(hk_adapters);
110 if (hk_adapter != NULL)
111 RegCloseKey(hk_adapter);
113 return min_mtu;
116 /* syscfg_GetIFInfo
118 * Retrieve IP addresses, subnet masks, MTU sizes, and flags for all
119 * configured interfaces.
121 * Arguments:
122 * IN/OUT:
123 * count - in is max size of arrays. out is number of elements used.
125 * OUT:
126 * addrs - array of configured IP addresses, in host order.
127 * masks - array of subnet masks, in host order.
128 * mtus - array of MTU sizes.
129 * flags - array of flags.
131 * Return Value:
132 * Total number of configured interfaces (>= count) or -1 on error.
135 int syscfg_GetIFInfo(int *count, int *addrs, int *masks, int *mtus, int *flags)
137 PMIB_IPADDRTABLE pIpAddrTable = NULL;
138 DWORD validAddrs = 0;
140 int maxCount = *count;
141 int nConfig = 0;
142 PIP_ADAPTER_ADDRESSES pAddresses, cAddress;
143 PMIB_IPADDRTABLE pIpTbl;
144 ULONG outBufLen = 0;
145 DWORD dwRetVal = 0;
146 int n = 0;
147 DWORD i;
149 HMODULE hIpHlp;
150 DWORD (WINAPI *pGetAdaptersAddresses)(ULONG, DWORD, PVOID,
151 PIP_ADAPTER_ADDRESSES, PULONG) = 0;
153 hIpHlp = LoadLibrary("iphlpapi");
154 if (hIpHlp != NULL) {
155 (FARPROC) pGetAdaptersAddresses = GetProcAddress(hIpHlp, "GetAdaptersAddresses");
156 if (pGetAdaptersAddresses == NULL)
157 FreeLibrary(hIpHlp);
160 if (pGetAdaptersAddresses == NULL)
161 return syscfg_GetIFInfo_2000(count, addrs, masks, mtus, flags);
163 /* first pass to get the required size of the IP table */
164 pIpTbl = (PMIB_IPADDRTABLE) malloc(sizeof(MIB_IPADDRTABLE));
165 outBufLen = sizeof(MIB_IPADDRTABLE);
167 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
168 if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
169 /* this should have failed with an insufficient buffer because we
170 didn't give any space to place the IP addresses */
171 free(pIpTbl);
172 *count = 0;
173 nConfig = -1;
174 goto done;
177 /* second pass to get the actual data */
178 free(pIpTbl);
179 pIpTbl = (PMIB_IPADDRTABLE) malloc(outBufLen);
181 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
182 if (dwRetVal != NO_ERROR) {
183 free(pIpTbl);
184 *count = 0;
185 nConfig = -1;
186 goto done;
189 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(sizeof(IP_ADAPTER_ADDRESSES));
191 /* first call gets required buffer size */
192 if (pGetAdaptersAddresses(AF_INET,
194 NULL,
195 pAddresses,
196 &outBufLen) == ERROR_BUFFER_OVERFLOW)
198 free(pAddresses);
199 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen);
200 } else {
201 free(pIpTbl);
202 *count = 0;
203 nConfig = -1;
204 goto done;
207 /* second call to get the actual data */
208 if ((dwRetVal = pGetAdaptersAddresses(AF_INET,
210 NULL,
211 pAddresses,
212 &outBufLen)) == NO_ERROR)
214 /* we have a list of addresses. go through them and figure out
215 the IP addresses */
216 for (cAddress = pAddresses; cAddress; cAddress = cAddress->Next) {
218 /* skip software loopback adapters */
219 if (cAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
220 continue;
222 /* also skip interfaces that are not up */
223 if (cAddress->OperStatus != 1)
224 continue;
226 /* starting with the AdapterName, which is actually the adapter
227 instance GUID, check if this is a MS loopback device */
228 if (IsLoopback(cAddress->AdapterName))
229 continue;
231 /* ok. looks good. Now fish out all the addresses from the
232 address table corresponding to the interface, and add them
233 to the list */
234 for (i=0;i<pIpTbl->dwNumEntries;i++) {
235 if (pIpTbl->table[i].dwIndex == cAddress->IfIndex)
237 DWORD if_mtu;
239 if_mtu = GetMTUForAddress(cAddress);
240 #ifdef DEBUG
241 if (if_mtu < cAddress->Mtu) {
242 char s[1024];
243 StringCbPrintf(s, sizeof(s), "MTU from registry is less than MTU from adapter address (%d vs %d)\n", if_mtu, cAddress->Mtu);
244 OutputDebugString(s);
246 #endif
248 if (n < maxCount) {
249 addrs[n] = ntohl(pIpTbl->table[i].dwAddr);
250 masks[n] = ntohl(pIpTbl->table[i].dwMask);
251 mtus[n] = min(cAddress->Mtu, if_mtu);
252 flags[n] = 0;
253 n++;
255 nConfig++;
260 free(pAddresses);
261 free(pIpTbl);
263 *count = n;
264 } else {
265 /* again. this is bad */
266 free(pAddresses);
267 free(pIpTbl);
268 *count = 0;
269 nConfig = -1;
272 done:
273 FreeLibrary(hIpHlp);
274 return nConfig;
277 static int IsLoopback(char * guid)
279 int isloopback = FALSE;
281 HKEY hkNet = NULL;
282 HKEY hkDev = NULL;
283 HKEY hkDevConn = NULL;
284 HKEY hkEnum = NULL;
285 HKEY hkAdapter = NULL;
287 char pnpIns[MAX_PATH];
288 char hwId[MAX_PATH];
289 char service[MAX_PATH];
291 DWORD size;
293 /* Open the network adapters key */
294 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hkNet)))
295 goto _exit;
297 /* open the guid key */
298 if (FAILED(RegOpenKeyEx(hkNet, guid, 0, KEY_READ, &hkDev)))
299 goto _exit;
301 /* then the connection */
302 if (FAILED(RegOpenKeyEx(hkDev, "Connection", 0, KEY_READ, &hkDevConn)))
303 goto _exit;
305 /* and find out the plug-n-play instance ID */
306 size = MAX_PATH;
307 if (FAILED(RegQueryValueEx(hkDevConn, "PnpInstanceID", NULL, NULL, pnpIns, &size)))
308 goto _exit;
310 /* now look in the device ENUM */
311 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum", 0, KEY_READ, &hkEnum)))
312 goto _exit;
314 /* for the instance that we found above */
315 if (FAILED(RegOpenKeyEx(hkEnum, pnpIns, 0, KEY_READ, &hkAdapter)))
316 goto _exit;
318 /* and fetch the harware ID */
319 size = MAX_PATH;
320 if (FAILED(RegQueryValueEx(hkAdapter, "HardwareID", NULL, NULL, hwId, &size)))
321 goto _exit;
323 size = MAX_PATH;
324 if (FAILED(RegQueryValueEx(hkAdapter, "Service", NULL, NULL, service, &size)))
325 goto _exit;
327 /* and see if it is the loopback adapter */
328 if (!stricmp(hwId, "*msloop") || !stricmp(service, "msloop"))
329 isloopback = TRUE;
331 _exit:
332 if (hkAdapter)
333 RegCloseKey(hkAdapter);
334 if (hkEnum)
335 RegCloseKey(hkEnum);
336 if (hkDevConn)
337 RegCloseKey(hkDevConn);
338 if (hkDev)
339 RegCloseKey(hkDev);
340 if (hkNet)
341 RegCloseKey(hkNet);
343 return isloopback;
346 static int GetInterfaceList(HKEY skey, char **list);
347 static char *GetNextInterface(char *iflist);
348 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask);
350 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags)
352 int maxCount = *count;
353 char *IFListBase = NULL;
354 char *IFList, *ifname;
355 HKEY skey;
356 int i, n, nConfig;
358 if (RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_IPSRV_KEY,
359 KEY_READ, 0, &skey, NULL))
360 return -1;
362 if ((nConfig = GetInterfaceList(skey, &IFListBase)) < 0) {
363 (void) RegCloseKey(skey);
364 return -1;
367 IFList = IFListBase;
368 n = 0;
370 while ((n < maxCount) && (ifname = GetNextInterface(IFList))) {
371 if (!IsLoopback(ifname) && GetIP(skey, ifname, &addrs[n], &masks[n]) == 0 && addrs[n] != 0) {
372 n++;
373 } else {
374 maxCount--;
376 IFList = ifname;
379 /* And until we get mtu's and flags */
380 for (i = 0; i < n; i++) {
381 mtus[i] = 1500;
382 flags[i] = 0;
385 (void) RegCloseKey(skey);
386 free(IFListBase);
388 *count = n;
389 return nConfig;
393 /* GetInterfaceList
395 * Get interface list; list is represented as a multistring.
396 * Returns number of elements in interface list or -1 on error.
398 static int GetInterfaceList(HKEY skey, char **list)
400 HKEY key;
401 long status;
402 char *str = NULL;
403 int size;
404 DWORD valType;
406 if (RegOpenKeyAlt(skey, AFSREG_IPSRV_IFACELIST_SUBKEY,
407 KEY_READ, 0, &key, NULL))
408 return -1;
410 status = RegQueryValueAlt(key, AFSREG_IPSRV_IFACELIST_BIND_VALUE,
411 &valType, &str, NULL);
412 (void) RegCloseKey(key);
413 if (status || (valType != REG_MULTI_SZ))
414 return -1;
416 /* Count strings in multistring. */
417 size = 0;
419 if (*str != '\0') {
420 int i;
422 for (i = 1; ; i++) {
423 if (str[i] == '\0') {
424 /* hit end of string */
425 size++;
426 i++;
427 if (str[i] == '\0') {
428 /* hit end of multistring */
429 break;
434 *list = str;
435 return size;
439 /* GetNextInterface
441 * Parse interface list. In first call to GetNextInterface(), iflist is
442 * the list returned by GetInterfaceList(); in successive calls, iflist is
443 * the pointer returned by the previous call to GetNextInterface().
445 * Returns pointer to next adapter name, or NULL if done.
448 static char *GetNextInterface(char *iflist)
450 char *ifname;
452 /* interface substrings are assumed to be of form \Device\<adapter name>
453 * \Tcpip\Parameters\Interfaces\<adapter name>
455 ifname = strrchr(iflist, '\\');
457 if (!ifname) {
458 /* subsequent (not first) call; advance to next interface substring */
459 iflist += strlen(iflist) + 1;
460 /* iflist now points to next interface or end-of-multistring char */
461 ifname = strrchr(iflist, '\\');
464 if (ifname) {
465 /* advance to first character of adapter name */
466 ifname++;
469 return ifname;
473 /* GetIP
475 * Get IP address associated with interface (adapter name).
476 * Returns 0 on success and -1 on error.
479 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask)
481 HKEY key;
482 char *s;
483 long status;
484 int len;
485 char *ipStr = NULL;
486 char *snMask = NULL;
487 DWORD valType;
488 DWORD dwDHCP;
489 DWORD dwLease;
490 DWORD dwSize;
492 len = (int) strlen(ifname) + 1 + sizeof(AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
493 s = malloc(len);
494 if (!s)
495 return -1;
497 sprintf(s, "%s\\%s", ifname, AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
499 status = RegOpenKeyAlt(skey, s, KEY_READ, 0, &key, NULL);
500 free(s);
502 if (status)
503 return -1;
505 dwSize = sizeof(DWORD);
506 status = RegQueryValueEx(key, "EnableDHCP", NULL,
507 &valType, (LPBYTE) &dwDHCP, &dwSize);
508 if (status || (valType != REG_DWORD))
509 dwDHCP = 0;
511 if (dwDHCP == 0) {
512 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_ADDR_VALUE,
513 &valType, &ipStr, NULL);
514 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
515 if (ipStr) free(ipStr);
516 (void) RegCloseKey(key);
517 return -1;
520 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_MASK_VALUE,
521 &valType, &snMask, NULL);
522 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
523 if (snMask) free(snMask);
524 snMask = NULL;
526 } else {
527 /* adapter configured via DHCP; address/mask in alternate values */
528 dwSize = sizeof(DWORD);
529 status = RegQueryValueEx(key, "Lease", NULL,
530 &valType, (LPBYTE)&dwLease, &dwSize);
531 if (status || (valType != REG_DWORD) || dwLease == 0) {
532 (void) RegCloseKey(key);
533 return -1;
536 status = RegQueryValueAlt(key,
537 AFSREG_IPSRV_ADAPTER_PARAM_DHCPADDR_VALUE,
538 &valType, &ipStr, NULL);
540 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
541 if (ipStr) free(ipStr);
542 (void) RegCloseKey(key);
543 return -1;
546 status = RegQueryValueAlt(key,
547 AFSREG_IPSRV_ADAPTER_PARAM_DHCPMASK_VALUE,
548 &valType, &snMask, NULL);
550 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
551 if (snMask) free(snMask);
552 snMask = NULL;
556 /* convert ip and subnet. */
557 *addr = (int)inet_addr(ipStr);
558 *addr = ntohl(*addr);
559 free(ipStr);
561 if (snMask) {
562 *mask = (int)inet_addr(snMask);
563 *mask = ntohl(*mask);
564 free(snMask);
565 } else {
566 *mask = 0;
569 (void) RegCloseKey(key);
571 return 0;