s3-privileges: add privilege_delete_account().
[ira/wip.git] / source3 / lib / interfaces.c
1 /*
2    Unix SMB/CIFS implementation.
3    return a list of network interfaces
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Jeremy Allison 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program 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
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /****************************************************************************
24  Create a struct sockaddr_storage with the netmask bits set to 1.
25 ****************************************************************************/
26
27 bool make_netmask(struct sockaddr_storage *pss_out,
28                         const struct sockaddr_storage *pss_in,
29                         unsigned long masklen)
30 {
31         *pss_out = *pss_in;
32         /* Now apply masklen bits of mask. */
33 #if defined(HAVE_IPV6)
34         if (pss_in->ss_family == AF_INET6) {
35                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
36                 unsigned int i;
37
38                 if (masklen > 128) {
39                         return false;
40                 }
41                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
42                         *p++ = 0xff;
43                 }
44                 /* Deal with the partial byte. */
45                 *p++ &= (0xff & ~(0xff>>masklen));
46                 i++;
47                 for (;i < sizeof(struct in6_addr); i++) {
48                         *p++ = '\0';
49                 }
50                 return true;
51         }
52 #endif
53         if (pss_in->ss_family == AF_INET) {
54                 if (masklen > 32) {
55                         return false;
56                 }
57                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
58                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
59                 return true;
60         }
61         return false;
62 }
63
64 /****************************************************************************
65  Create a struct sockaddr_storage set to the broadcast or network adress from
66  an incoming sockaddr_storage.
67 ****************************************************************************/
68
69 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
70                         const struct sockaddr_storage *pss_in,
71                         const struct sockaddr_storage *nmask,
72                         bool make_bcast_p)
73 {
74         unsigned int i = 0, len = 0;
75         char *pmask = NULL;
76         char *p = NULL;
77         *pss_out = *pss_in;
78
79         /* Set all zero netmask bits to 1. */
80 #if defined(HAVE_IPV6)
81         if (pss_in->ss_family == AF_INET6) {
82                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
83                 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
84                 len = 16;
85         }
86 #endif
87         if (pss_in->ss_family == AF_INET) {
88                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
89                 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
90                 len = 4;
91         }
92
93         for (i = 0; i < len; i++, p++, pmask++) {
94                 if (make_bcast_p) {
95                         *p = (*p & *pmask) | (*pmask ^ 0xff);
96                 } else {
97                         /* make_net */
98                         *p = (*p & *pmask);
99                 }
100         }
101 }
102
103 void make_bcast(struct sockaddr_storage *pss_out,
104                         const struct sockaddr_storage *pss_in,
105                         const struct sockaddr_storage *nmask)
106 {
107         make_bcast_or_net(pss_out, pss_in, nmask, true);
108 }
109
110 void make_net(struct sockaddr_storage *pss_out,
111                         const struct sockaddr_storage *pss_in,
112                         const struct sockaddr_storage *nmask)
113 {
114         make_bcast_or_net(pss_out, pss_in, nmask, false);
115 }
116
117 /****************************************************************************
118  Try the "standard" getifaddrs/freeifaddrs interfaces.
119  Also gets IPv6 interfaces.
120 ****************************************************************************/
121
122 /****************************************************************************
123  Get the netmask address for a local interface.
124 ****************************************************************************/
125
126 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
127 {
128         struct ifaddrs *iflist = NULL;
129         struct ifaddrs *ifptr = NULL;
130         int total = 0;
131         size_t copy_size;
132
133         if (getifaddrs(&iflist) < 0) {
134                 return -1;
135         }
136
137         /* Loop through interfaces, looking for given IP address */
138         for (ifptr = iflist, total = 0;
139                         ifptr != NULL && total < max_interfaces;
140                         ifptr = ifptr->ifa_next) {
141
142                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
143
144                 copy_size = sizeof(struct sockaddr_in);
145
146                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
147                         continue;
148                 }
149
150                 ifaces[total].flags = ifptr->ifa_flags;
151
152                 /* Check the interface is up. */
153                 if (!(ifaces[total].flags & IFF_UP)) {
154                         continue;
155                 }
156
157 #if defined(HAVE_IPV6)
158                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
159                         copy_size = sizeof(struct sockaddr_in6);
160                 }
161 #endif
162
163                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
164                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
165
166                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
167                         make_bcast(&ifaces[total].bcast,
168                                 &ifaces[total].ip,
169                                 &ifaces[total].netmask);
170                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
171                                ifptr->ifa_dstaddr ) {
172                         memcpy(&ifaces[total].bcast,
173                                 ifptr->ifa_dstaddr,
174                                 copy_size);
175                 } else {
176                         continue;
177                 }
178
179                 strlcpy(ifaces[total].name, ifptr->ifa_name,
180                         sizeof(ifaces[total].name));
181                 total++;
182         }
183
184         freeifaddrs(iflist);
185
186         return total;
187 }
188
189 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
190 {
191         int r;
192
193 #if defined(HAVE_IPV6)
194         /*
195          * If we have IPv6 - sort these interfaces lower
196          * than any IPv4 ones.
197          */
198         if (i1->ip.ss_family == AF_INET6 &&
199                         i2->ip.ss_family == AF_INET) {
200                 return -1;
201         } else if (i1->ip.ss_family == AF_INET &&
202                         i2->ip.ss_family == AF_INET6) {
203                 return 1;
204         }
205
206         if (i1->ip.ss_family == AF_INET6) {
207                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
208                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
209
210                 r = memcmp(&s1->sin6_addr,
211                                 &s2->sin6_addr,
212                                 sizeof(struct in6_addr));
213                 if (r) {
214                         return r;
215                 }
216
217                 s1 = (struct sockaddr_in6 *)&i1->netmask;
218                 s2 = (struct sockaddr_in6 *)&i2->netmask;
219
220                 r = memcmp(&s1->sin6_addr,
221                                 &s2->sin6_addr,
222                                 sizeof(struct in6_addr));
223                 if (r) {
224                         return r;
225                 }
226         }
227 #endif
228
229         /* AIX uses __ss_family instead of ss_family inside of
230            sockaddr_storage. Instead of trying to figure out which field to
231            use, we can just cast it to a sockaddr.
232          */
233
234         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
235                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
236                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
237
238                 r = ntohl(s1->sin_addr.s_addr) -
239                         ntohl(s2->sin_addr.s_addr);
240                 if (r) {
241                         return r;
242                 }
243
244                 s1 = (struct sockaddr_in *)&i1->netmask;
245                 s2 = (struct sockaddr_in *)&i2->netmask;
246
247                 return ntohl(s1->sin_addr.s_addr) -
248                         ntohl(s2->sin_addr.s_addr);
249         }
250         return 0;
251 }
252
253 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
254 /* this wrapper is used to remove duplicates from the interface list generated
255    above */
256 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
257 {
258         int total, i, j;
259
260         total = _get_interfaces(ifaces, max_interfaces);
261         if (total <= 0) return total;
262
263         /* now we need to remove duplicates */
264         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
265
266         for (i=1;i<total;) {
267                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
268                         for (j=i-1;j<total-1;j++) {
269                                 ifaces[j] = ifaces[j+1];
270                         }
271                         total--;
272                 } else {
273                         i++;
274                 }
275         }
276
277         return total;
278 }
279