Imported Upstream version 1.6.6
[debian/sudo] / interfaces.c
1 /*
2  * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * 4. Products derived from this software may not be called "Sudo" nor
20  *    may "Sudo" appear in their names without specific prior written
21  *    permission from the author.
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 /*
36  * Supress a warning w/ gcc on Digital UN*X.
37  * The system headers should really do this....
38  */
39 #if defined(__osf__) && !defined(__cplusplus)
40 struct mbuf;
41 struct rtentry;
42 #endif
43
44 #include "config.h"
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <sys/param.h>
49 #include <sys/time.h>
50 #include <sys/ioctl.h>
51 #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
52 # include <sys/sockio.h>
53 #endif
54 #include <stdio.h>
55 #ifdef STDC_HEADERS
56 # include <stdlib.h>
57 # include <stddef.h>
58 #else
59 # ifdef HAVE_STDLIB_H
60 #  include <stdlib.h>
61 # endif
62 #endif /* STDC_HEADERS */
63 #ifdef HAVE_STRING_H
64 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
65 #  include <memory.h>
66 # endif
67 # include <string.h>
68 #else
69 # ifdef HAVE_STRINGS_H
70 #  include <strings.h>
71 # endif
72 #endif /* HAVE_STRING_H */
73 #ifdef HAVE_UNISTD_H
74 # include <unistd.h>
75 #endif /* HAVE_UNISTD_H */
76 #include <netdb.h>
77 #include <errno.h>
78 #ifdef _ISC
79 # include <sys/stream.h>
80 # include <sys/sioctl.h>
81 # include <sys/stropts.h>
82 # include <net/errno.h>
83 # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
84                                  strioctl.ic_dp=(param);\
85                                  strioctl.ic_timout=0;\
86                                  strioctl.ic_len=(len);}
87 #endif /* _ISC */
88 #ifdef _MIPS
89 # include <net/soioctl.h>
90 #endif /* _MIPS */
91 #include <netinet/in.h>
92 #include <arpa/inet.h>
93 #include <net/if.h>
94 #ifdef HAVE_GETIFADDRS
95 # include <ifaddrs.h>
96 #endif
97
98 #include "sudo.h"
99 #include "interfaces.h"
100
101 #ifndef lint
102 static const char rcsid[] = "$Sudo: interfaces.c,v 1.63 2002/01/18 19:17:07 millert Exp $";
103 #endif /* lint */
104
105
106 #ifdef HAVE_GETIFADDRS
107
108 /*
109  * Allocate and fill in the interfaces global variable with the
110  * machine's ip addresses and netmasks.
111  */
112 void
113 load_interfaces()
114 {
115     struct ifaddrs *ifa, *ifaddrs;
116     /* XXX - sockaddr_in6 sin6; */
117     struct sockaddr_in *sin;
118     int i;
119
120     if (getifaddrs(&ifaddrs))
121         return;
122
123     /* Allocate space for the interfaces list. */
124     for (ifa = ifaddrs; ifa -> ifa_next; ifa = ifa -> ifa_next) {
125         /* Skip interfaces marked "down" and "loopback". */
126         if (ifa->ifa_addr == NULL || !(ifa->ifa_flags & IFF_UP) ||
127             (ifa->ifa_flags & IFF_LOOPBACK))
128             continue;
129
130         switch(ifa->ifa_addr->sa_family) {
131             /* XXX - AF_INET6 */
132             case AF_INET:
133                 num_interfaces++;
134                 break;
135         }
136     }
137     interfaces =
138         (struct interface *) emalloc(sizeof(struct interface) * num_interfaces);
139
140     /* Store the ip addr / netmask pairs. */
141     for (ifa = ifaddrs, i = 0; ifa -> ifa_next; ifa = ifa -> ifa_next) {
142         /* Skip interfaces marked "down" and "loopback". */
143         if (ifa->ifa_addr == NULL || !(ifa->ifa_flags & IFF_UP) ||
144             (ifa->ifa_flags & IFF_LOOPBACK))
145                 continue;
146
147         switch(ifa->ifa_addr->sa_family) {
148             /* XXX - AF_INET6 */
149             case AF_INET:
150                 sin = (struct sockaddr_in *)ifa->ifa_addr;
151                 memcpy(&interfaces[i].addr, &sin->sin_addr,
152                     sizeof(struct in_addr));
153                 sin = (struct sockaddr_in *)ifa->ifa_netmask;
154                 memcpy(&interfaces[i].netmask, &sin->sin_addr,
155                     sizeof(struct in_addr));
156                 i++;
157                 break;
158         }
159     }
160 #ifdef HAVE_FREEIFADDRS
161     freeifaddrs(ifaddrs);
162 #else
163     free(ifaddrs);
164 #endif
165 }
166
167 #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
168
169 /*
170  * Allocate and fill in the interfaces global variable with the
171  * machine's ip addresses and netmasks.
172  */
173 void
174 load_interfaces()
175 {
176     struct ifconf *ifconf;
177     struct ifreq *ifr, ifr_tmp;
178     struct sockaddr_in *sin;
179     int sock, n, i;
180     size_t len = sizeof(struct ifconf) + BUFSIZ;
181     char *previfname = "", *ifconf_buf = NULL;
182 #ifdef _ISC
183     struct strioctl strioctl;
184 #endif /* _ISC */
185
186     sock = socket(AF_INET, SOCK_DGRAM, 0);
187     if (sock < 0) {
188         (void) fprintf(stderr, "%s: cannot open socket: %s\n",
189             Argv[0], strerror(errno));
190         exit(1);
191     }
192
193     /*
194      * Get interface configuration or return (leaving num_interfaces 0)
195      */
196     for (;;) {
197         ifconf_buf = erealloc(ifconf_buf, len);
198         ifconf = (struct ifconf *) ifconf_buf;
199         ifconf->ifc_len = len - sizeof(struct ifconf);
200         ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
201
202         /* Networking may not be installed in kernel... */
203 #ifdef _ISC
204         STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
205         if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
206 #else
207         if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0) {
208 #endif /* _ISC */
209             free(ifconf_buf);
210             (void) close(sock);
211             return;
212         }
213
214         /* Break out of loop if we have a big enough buffer. */
215         if (ifconf->ifc_len + sizeof(struct ifreq) < len)
216             break;
217         len += BUFSIZ;
218     }
219
220     /* Allocate space for the maximum number of interfaces that could exist. */
221     n = ifconf->ifc_len / sizeof(struct ifreq);
222     interfaces = (struct interface *) emalloc(sizeof(struct interface) * n);
223
224     /* For each interface, store the ip address and netmask. */
225     for (i = 0; i < ifconf->ifc_len; ) {
226         /* Get a pointer to the current interface. */
227         ifr = (struct ifreq *) &ifconf->ifc_buf[i];
228
229         /* Set i to the subscript of the next interface. */
230         i += sizeof(struct ifreq);
231 #ifdef HAVE_SA_LEN
232         if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
233             i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
234 #endif /* HAVE_SA_LEN */
235
236         /* Skip duplicates and interfaces with NULL addresses. */
237         sin = (struct sockaddr_in *) &ifr->ifr_addr;
238         if (sin->sin_addr.s_addr == 0 ||
239             strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
240             continue;
241
242         if (ifr->ifr_addr.sa_family != AF_INET)
243                 continue;
244
245 #ifdef SIOCGIFFLAGS
246         memset(&ifr_tmp, 0, sizeof(ifr_tmp));
247         strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
248         if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
249 #endif
250             ifr_tmp = *ifr;
251         
252         /* Skip interfaces marked "down" and "loopback". */
253         if (!(ifr_tmp.ifr_flags & IFF_UP) || (ifr_tmp.ifr_flags & IFF_LOOPBACK))
254                 continue;
255
256         sin = (struct sockaddr_in *) &ifr->ifr_addr;
257         interfaces[num_interfaces].addr.s_addr = sin->sin_addr.s_addr;
258
259         /* Stash the name of the interface we saved. */
260         previfname = ifr->ifr_name;
261
262         /* Get the netmask. */
263         (void) memset(&ifr_tmp, 0, sizeof(ifr_tmp));
264         strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
265 #ifdef SIOCGIFNETMASK
266 #ifdef _ISC
267         STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
268         if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) {
269 #else
270         if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) {
271 #endif /* _ISC */
272             sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
273
274             interfaces[num_interfaces].netmask.s_addr = sin->sin_addr.s_addr;
275         } else {
276 #else
277         {
278 #endif /* SIOCGIFNETMASK */
279             if (IN_CLASSC(interfaces[num_interfaces].addr.s_addr))
280                 interfaces[num_interfaces].netmask.s_addr = htonl(IN_CLASSC_NET);
281             else if (IN_CLASSB(interfaces[num_interfaces].addr.s_addr))
282                 interfaces[num_interfaces].netmask.s_addr = htonl(IN_CLASSB_NET);
283             else
284                 interfaces[num_interfaces].netmask.s_addr = htonl(IN_CLASSA_NET);
285         }
286
287         /* Only now can we be sure it was a good/interesting interface. */
288         num_interfaces++;
289     }
290
291     /* If the expected size < real size, realloc the array. */
292     if (n != num_interfaces) {
293         if (num_interfaces != 0)
294             interfaces = (struct interface *) erealloc(interfaces,
295                 sizeof(struct interface) * num_interfaces);
296         else
297             free(interfaces);
298     }
299     free(ifconf_buf);
300     (void) close(sock);
301 }
302
303 #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
304
305 /*
306  * Stub function for those without SIOCGIFCONF
307  */
308 void
309 load_interfaces()
310 {
311     return;
312 }
313
314 #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
315
316 void
317 dump_interfaces()
318 {
319     int i;
320
321     puts("Local IP address and netmask pairs:");
322     for (i = 0; i < num_interfaces; i++)
323         printf("\t%s / 0x%x\n", inet_ntoa(interfaces[i].addr),
324             ntohl(interfaces[i].netmask.s_addr));
325 }