ws2_32: name is never NULL as array (Coverity).
[wine] / programs / ipconfig / ipconfig.c
1 /*
2  * IP configuration utility
3  *
4  * Copyright 2008 Andrew Riedi
5  * Copyright 2010 Andrew Nguyen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <windows.h>
23 #include <iphlpapi.h>
24 #include <wine/unicode.h>
25
26 #include "ipconfig.h"
27
28 static int ipconfig_vprintfW(const WCHAR *msg, va_list va_args)
29 {
30     int wlen;
31     DWORD count, ret;
32     WCHAR msg_buffer[8192];
33
34     wlen = vsprintfW(msg_buffer, msg, va_args);
35
36     ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
37     if (!ret)
38     {
39         DWORD len;
40         char *msgA;
41
42         len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
43             NULL, 0, NULL, NULL);
44         msgA = HeapAlloc(GetProcessHeap(), 0, len);
45         if (!msgA)
46             return 0;
47
48         WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
49             NULL, NULL);
50         WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
51         HeapFree(GetProcessHeap(), 0, msgA);
52     }
53
54     return count;
55 }
56
57 static int ipconfig_printfW(const WCHAR *msg, ...)
58 {
59     va_list va_args;
60     int len;
61
62     va_start(va_args, msg);
63     len = ipconfig_vprintfW(msg, va_args);
64     va_end(va_args);
65
66     return len;
67 }
68
69 static int ipconfig_message_printfW(int msg, ...)
70 {
71     va_list va_args;
72     WCHAR msg_buffer[8192];
73     int len;
74
75     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
76         sizeof(msg_buffer)/sizeof(WCHAR));
77
78     va_start(va_args, msg);
79     len = ipconfig_vprintfW(msg_buffer, va_args);
80     va_end(va_args);
81
82     return len;
83 }
84
85 static int ipconfig_message(int msg)
86 {
87     static const WCHAR formatW[] = {'%','s',0};
88     WCHAR msg_buffer[8192];
89
90     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
91         sizeof(msg_buffer)/sizeof(WCHAR));
92
93     return ipconfig_printfW(formatW, msg_buffer);
94 }
95
96 static const WCHAR *iftype_to_string(DWORD type)
97 {
98     static WCHAR msg_buffer[50];
99
100     int msg;
101
102     switch (type)
103     {
104     case IF_TYPE_ETHERNET_CSMACD:
105     /* The loopback adapter appears as an Ethernet device. */
106     case IF_TYPE_SOFTWARE_LOOPBACK:
107         msg = STRING_ETHERNET;
108         break;
109     default:
110         msg = STRING_UNKNOWN;
111     }
112
113     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
114         sizeof(msg_buffer)/sizeof(WCHAR));
115
116     return msg_buffer;
117 }
118
119 static void print_field(int msg, const WCHAR *value)
120 {
121     static const WCHAR formatW[] = {' ',' ',' ',' ','%','s',':',' ','%','s','\n',0};
122
123     WCHAR field[] = {'.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',
124                      ' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ',0};
125     WCHAR name_buffer[sizeof(field)/sizeof(WCHAR)];
126
127     LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, sizeof(name_buffer)/sizeof(WCHAR));
128     memcpy(field, name_buffer, sizeof(WCHAR) * min(strlenW(name_buffer), sizeof(field)/sizeof(WCHAR) - 1));
129
130     ipconfig_printfW(formatW, field, value);
131 }
132
133 static void print_value(const WCHAR *value)
134 {
135     static const WCHAR formatW[] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
136                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
137                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
138                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
139                                     '%','s','\n',0};
140
141     ipconfig_printfW(formatW, value);
142 }
143
144 static BOOL socket_address_to_string(WCHAR *buf, DWORD len, SOCKET_ADDRESS *addr)
145 {
146     return WSAAddressToStringW(addr->lpSockaddr,
147                                addr->iSockaddrLength, NULL,
148                                buf, &len) == 0;
149 }
150
151 static void print_basic_information(void)
152 {
153     IP_ADAPTER_ADDRESSES *adapters;
154     ULONG out = 0;
155
156     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
157                              NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
158     {
159         adapters = HeapAlloc(GetProcessHeap(), 0, out);
160         if (!adapters)
161             exit(1);
162
163         if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
164                                  NULL, adapters, &out) == ERROR_SUCCESS)
165         {
166             IP_ADAPTER_ADDRESSES *p;
167
168             for (p = adapters; p; p = p->Next)
169             {
170                 static const WCHAR newlineW[] = {'\n',0};
171                 static const WCHAR emptyW[] = {0};
172
173                 IP_ADAPTER_UNICAST_ADDRESS *addr;
174                 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
175                 WCHAR addr_buf[54];
176
177                 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
178                 ipconfig_printfW(newlineW);
179                 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
180
181                 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
182                 {
183                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
184                         print_field(STRING_IP_ADDRESS, addr_buf);
185                     /* FIXME: Output corresponding subnet mask. */
186                 }
187
188                 if (p->FirstGatewayAddress)
189                 {
190                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
191                         print_field(STRING_DEFAULT_GATEWAY, addr_buf);
192
193                     for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
194                     {
195                         if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
196                             print_value(addr_buf);
197                     }
198                 }
199                 else
200                     print_field(STRING_DEFAULT_GATEWAY, emptyW);
201
202                 ipconfig_printfW(newlineW);
203             }
204         }
205
206         HeapFree(GetProcessHeap(), 0, adapters);
207     }
208 }
209
210 static const WCHAR *nodetype_to_string(DWORD type)
211 {
212     static WCHAR msg_buffer[50];
213
214     int msg;
215
216     switch (type)
217     {
218     case BROADCAST_NODETYPE:
219         msg = STRING_BROADCAST;
220         break;
221     case PEER_TO_PEER_NODETYPE:
222         msg = STRING_PEER_TO_PEER;
223         break;
224     case MIXED_NODETYPE:
225         msg = STRING_MIXED;
226         break;
227     case HYBRID_NODETYPE:
228         msg = STRING_HYBRID;
229         break;
230     default:
231         msg = STRING_UNKNOWN;
232     }
233
234     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
235         sizeof(msg_buffer)/sizeof(WCHAR));
236
237     return msg_buffer;
238 }
239
240 static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len)
241 {
242     static const WCHAR fmtW[] = {'%','0','2','X','-',0};
243     static const WCHAR fmt2W[] = {'%','0','2','X',0};
244
245     if (!len)
246         *buf = '\0';
247     else
248     {
249         WCHAR *p = buf;
250         DWORD i;
251
252         for (i = 0; i < len - 1; i++)
253         {
254             sprintfW(p, fmtW, addr[i]);
255             p += 3;
256         }
257         sprintfW(p, fmt2W, addr[i]);
258     }
259
260     return buf;
261 }
262
263 static const WCHAR *boolean_to_string(int value)
264 {
265     static WCHAR msg_buffer[15];
266
267     LoadStringW(GetModuleHandleW(NULL), value ? STRING_YES : STRING_NO,
268         msg_buffer, sizeof(msg_buffer)/sizeof(WCHAR));
269
270     return msg_buffer;
271 }
272
273 static void print_full_information(void)
274 {
275     static const WCHAR newlineW[] = {'\n',0};
276     static const WCHAR emptyW[] = {0};
277
278     FIXED_INFO *info;
279     IP_ADAPTER_ADDRESSES *adapters;
280     ULONG out = 0;
281
282     if (GetNetworkParams(NULL, &out) == ERROR_BUFFER_OVERFLOW)
283     {
284         info = HeapAlloc(GetProcessHeap(), 0, out);
285         if (!info)
286             exit(1);
287
288         if (GetNetworkParams(info, &out) == ERROR_SUCCESS)
289         {
290             WCHAR hostnameW[MAX_HOSTNAME_LEN + 4];
291
292             MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, sizeof(hostnameW)/sizeof(hostnameW[0]));
293             print_field(STRING_HOSTNAME, hostnameW);
294
295             /* FIXME: Output primary DNS suffix. */
296
297             print_field(STRING_NODE_TYPE, nodetype_to_string(info->NodeType));
298             print_field(STRING_IP_ROUTING, boolean_to_string(info->EnableRouting));
299
300             /* FIXME: Output WINS proxy status and DNS suffix search list. */
301
302             ipconfig_printfW(newlineW);
303         }
304
305         HeapFree(GetProcessHeap(), 0, info);
306     }
307
308     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
309                              NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
310     {
311         adapters = HeapAlloc(GetProcessHeap(), 0, out);
312         if (!adapters)
313             exit(1);
314
315         if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
316                                  NULL, adapters, &out) == ERROR_SUCCESS)
317         {
318             IP_ADAPTER_ADDRESSES *p;
319
320             for (p = adapters; p; p = p->Next)
321             {
322                 IP_ADAPTER_UNICAST_ADDRESS *addr;
323                 WCHAR physaddr_buf[3 * MAX_ADAPTER_ADDRESS_LENGTH];
324                 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
325                 WCHAR addr_buf[54];
326
327                 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
328                 ipconfig_printfW(newlineW);
329                 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
330                 print_field(STRING_DESCRIPTION, p->Description);
331                 print_field(STRING_PHYS_ADDR, physaddr_to_string(physaddr_buf, p->PhysicalAddress, p->PhysicalAddressLength));
332                 print_field(STRING_DHCP_ENABLED, boolean_to_string(p->Flags & IP_ADAPTER_DHCP_ENABLED));
333
334                 /* FIXME: Output autoconfiguration status. */
335
336                 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
337                 {
338                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
339                         print_field(STRING_IP_ADDRESS, addr_buf);
340                     /* FIXME: Output corresponding subnet mask. */
341                 }
342
343                 if (p->FirstGatewayAddress)
344                 {
345                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
346                         print_field(STRING_DEFAULT_GATEWAY, addr_buf);
347
348                     for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
349                     {
350                         if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
351                             print_value(addr_buf);
352                     }
353                 }
354                 else
355                     print_field(STRING_DEFAULT_GATEWAY, emptyW);
356
357                 ipconfig_printfW(newlineW);
358             }
359         }
360
361         HeapFree(GetProcessHeap(), 0, adapters);
362     }
363 }
364
365 int wmain(int argc, WCHAR *argv[])
366 {
367     static const WCHAR slashHelp[] = {'/','?',0};
368     static const WCHAR slashAll[] = {'/','a','l','l',0};
369
370     WSADATA data;
371
372     if (WSAStartup(MAKEWORD(2, 2), &data))
373         return 1;
374
375     if (argc > 1)
376     {
377         if (!strcmpW(slashHelp, argv[1]))
378         {
379             ipconfig_message(STRING_USAGE);
380             WSACleanup();
381             return 1;
382         }
383         else if (!strcmpiW(slashAll, argv[1]))
384         {
385             if (argv[2])
386             {
387                 ipconfig_message(STRING_INVALID_CMDLINE);
388                 ipconfig_message(STRING_USAGE);
389                 WSACleanup();
390                 return 1;
391             }
392
393             print_full_information();
394         }
395         else
396         {
397             ipconfig_message(STRING_INVALID_CMDLINE);
398             ipconfig_message(STRING_USAGE);
399             WSACleanup();
400             return 1;
401         }
402     }
403     else
404         print_basic_information();
405
406     WSACleanup();
407     return 0;
408 }