update copyright notices
[krb5.git] / src / lib / krb5 / os / localaddr.c
1 /*
2  * $Source$
3  * $Author$
4  *
5  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
6  * All Rights Reserved.
7  *
8  * For copying and distribution information, please see the file
9  * <krb5/copyright.h>.
10  *
11  * Return the protocol addresses supported by this host.
12  *
13  * XNS support is untested, but "Should just work".
14  */
15
16 #if !defined(lint) && !defined(SABER)
17 static char rcsid_getaddr_c[] =
18 "$Id$";
19 #endif  /* !lint & !SABER */
20
21 #include <krb5/krb5.h>
22 #include <krb5/osconf.h>
23
24 #include <krb5/ext-proto.h>
25
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <net/if.h>
29 #include <sys/errno.h>
30
31 /*
32  * The SIOCGIF* ioctls require a socket.
33  * It doesn't matter *what* kind of socket they use, but it has to be
34  * a socket.
35  *
36  * Of course, you can't just ask the kernel for a socket of arbitrary
37  * type; you have to ask for one with a valid type.
38  *
39  */
40 #ifdef KRB5_USE_INET
41
42 #include <netinet/in.h>
43
44 #ifndef USE_AF
45 #define USE_AF AF_INET
46 #define USE_TYPE SOCK_DGRAM
47 #define USE_PROTO 0
48 #endif
49
50 #endif
51
52 #ifdef KRB5_USE_NS
53
54 #include <netns/ns.h>
55
56 #ifndef USE_AF
57 #define USE_AF AF_NS
58 #define USE_TYPE SOCK_DGRAM
59 #define USE_PROTO 0             /* guess */
60 #endif
61
62 #endif
63 /*
64  * Add more address families here.
65  */
66
67 extern int errno;
68
69 /*
70  * Return all the protocol addresses of this host.
71  *
72  * We could kludge up something to return all addresses, assuming that
73  * they're valid kerberos protocol addresses, but we wouldn't know the
74  * real size of the sockaddr or know which part of it was actually the
75  * host part.
76  *
77  * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
78  */
79
80 krb5_error_code krb5_os_localaddr(addr)
81     krb5_address ***addr;
82 {
83     struct ifreq *ifr;
84     struct ifconf ifc;
85     int s, code, n, i;
86     char buf[1024];
87     krb5_address *addr_temp [ 1024/sizeof(struct ifreq) ];
88     int n_found;
89     int mem_err = 0;
90     
91     ifc.ifc_len = sizeof(buf);
92     ifc.ifc_buf = buf;
93
94     s = socket (USE_AF, USE_TYPE, USE_PROTO);
95     if (s < 0)
96         return errno;
97
98     code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
99     if (code < 0) {
100         int retval = errno;
101         close(s);
102         return retval;
103     }
104     n = ifc.ifc_len / sizeof (struct ifreq);
105     
106     for (n_found=0, i=0; i<n && ! mem_err; i++) {
107         krb5_address *address;
108         ifr = &ifc.ifc_req[i];
109         
110         if (ioctl (s, SIOCGIFFLAGS, (char *)ifr) < 0)
111             continue;
112
113 #ifdef IFF_LOOPBACK
114         if (ifr->ifr_flags & IFF_LOOPBACK) 
115             continue;
116 #endif
117
118         if (!(ifr->ifr_flags & IFF_UP)) 
119             /* interface is down; skip */
120             continue;
121
122         if (ioctl (s, SIOCGIFADDR, (char *)ifr) < 0)
123             /* can't get address */
124             continue;
125
126         /* ifr->ifr_addr has what we want! */
127         switch (ifr->ifr_addr.sa_family) {
128 #ifdef KRB5_USE_INET
129         case AF_INET:
130             {
131                 struct sockaddr_in *in =
132                     (struct sockaddr_in *)&ifr->ifr_addr;
133                 
134                 address = (krb5_address *)
135                     malloc (sizeof(krb5_address));
136                 if (address) {
137                     address->addrtype = ADDRTYPE_INET;
138                     address->length = sizeof(struct in_addr);
139                     address->contents = (unsigned char *)malloc(address->length);
140                     if (!address->contents) {
141                         xfree(address);
142                         address = 0;
143                         mem_err++;
144                     } else {
145                         memcpy ((char *)address->contents,
146                                 (char *)&in->sin_addr, 
147                                 address->length);
148                         break;
149                     }
150                 } else mem_err++;
151             }
152 #endif
153 #ifdef KRB5_USE_NS
154             case AF_XNS:
155             {  
156                 struct sockaddr_ns *ns =
157                     (struct sockaddr_ns *)&ifr->ifr_addr;                   
158                 address = (krb5_address *)
159                     malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
160                 if (address) {
161                     address->addrtype = ADDRTYPE_XNS; 
162
163                     /* XXX should we perhaps use ns_host instead? */
164
165                     address->length = sizeof(struct ns_addr);
166                     address->contents = (unsigned char *)malloc(address->length);
167                     if (!address->contents) {
168                         xfree(address);
169                         address = 0;
170                         mem_err++;
171                     } else {
172                         memcpy ((char *)address->contents,
173                                 (char *)&ns->sns_addr,
174                                 address->length);
175                         break;
176                     }
177                 } else mem_err++;
178                 break;
179             }
180 #endif
181         /*
182          * Add more address families here..
183          */
184         default:
185             continue;
186         }
187         if (address)
188             addr_temp[n_found++] = address;
189         address = 0;
190     }
191     close(s);
192
193     *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
194     if (*addr == 0)
195         mem_err++;
196     
197     if (mem_err) {
198         for (i=0; i<n_found; i++) {
199             xfree(addr_temp[i]);
200             addr_temp[i] = 0;
201         }
202         return ENOMEM;
203     }
204     
205     for (i=0; i<n_found; i++) {
206         (*addr)[i] = addr_temp[i];
207     }
208     (*addr)[n_found] = 0;
209     return 0;
210 }