libexport.a: Allow client_init() to fail instead of exit
[nfs-utils.git] / support / export / hostname.c
1 /*
2  * support/export/hostname.c
3  *
4  * Functions for hostname.
5  *
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 /*
13 #define TEST
14 */
15
16 #include <string.h>
17 #include <netdb.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <stdlib.h>
21 #include <xlog.h>
22 #ifdef TEST
23 #define xmalloc malloc
24 #else
25 #include "xmalloc.h"
26 #include "misc.h"
27 #endif
28
29 #define ALIGNMENT       sizeof (char *)
30
31 static int
32 align (int len, int al)
33 {
34   int i;
35   i = len % al;
36   if (i)
37     len += al - i;
38   return len;
39 }
40
41 struct hostent *
42 get_hostent (const char *addr, int len, int type)
43 {
44   struct hostent *cp;
45   int len_ent;
46   const char *name;
47   int len_name;
48   int num_aliases = 1;
49   int len_aliases = sizeof (char *);
50   int num_addr_list = 1;
51   int len_addr_list = sizeof (char *);
52   int pos;
53   struct in_addr *ipv4;
54
55   switch (type)
56     {
57     case AF_INET:
58       ipv4 = (struct in_addr *) addr;
59       name = inet_ntoa (*ipv4);
60       break;
61
62     default:
63       return NULL;
64     }
65
66   len_ent = align (sizeof (*cp), ALIGNMENT);
67   len_name = align (strlen (name) + 1, ALIGNMENT);
68
69   num_addr_list++;
70   len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
71
72   cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
73                                    + len_addr_list);
74
75   cp->h_addrtype = type;
76   cp->h_length = len;
77   pos = len_ent;
78   cp->h_name = (char *) &(((char *) cp) [pos]);
79   strcpy (cp->h_name, name);
80
81   pos += len_name;
82   cp->h_aliases = (char **) &(((char *) cp) [pos]);
83   pos += num_aliases * sizeof (char *);
84   cp->h_aliases [0] = NULL;
85
86   pos = len_ent + len_name + len_aliases;
87   cp->h_addr_list = (char **) &(((char *) cp) [pos]);
88   pos += num_addr_list * sizeof (char *);
89   cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
90   memcpy (cp->h_addr_list [0], addr, cp->h_length);
91   pos += align (cp->h_length, ALIGNMENT);
92   cp->h_addr_list [1] = NULL;
93
94   return cp;
95 }
96
97 struct hostent *
98 hostent_dup (struct hostent *hp)
99 {
100   int len_ent = align (sizeof (*hp), ALIGNMENT);
101   int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
102   int num_aliases = 1;
103   int len_aliases = sizeof (char *);
104   int num_addr_list = 1;
105   int len_addr_list = sizeof (char *);
106   int pos, i;
107   char **sp;
108   struct hostent *cp;
109
110   for (sp = hp->h_aliases; sp && *sp; sp++)
111     {
112       num_aliases++;
113       len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
114                      + sizeof (char *);
115     }
116
117   for (sp = hp->h_addr_list; *sp; sp++)
118     {
119       num_addr_list++;
120       len_addr_list += align (hp->h_length, ALIGNMENT)
121                        + sizeof (char *);
122     }
123
124   cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
125                                    + len_addr_list);
126
127   *cp = *hp;
128   pos = len_ent;
129   cp->h_name = (char *) &(((char *) cp) [pos]);
130   strcpy (cp->h_name, hp->h_name);
131
132   pos += len_name;
133   cp->h_aliases = (char **) &(((char *) cp) [pos]);
134   pos += num_aliases * sizeof (char *);
135   for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
136     if (sp && *sp)
137       {
138         cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
139         strcpy (cp->h_aliases [i], *sp);
140         pos += align (strlen (*sp) + 1, ALIGNMENT);
141       }
142     else
143       cp->h_aliases [i] = NULL;
144
145   pos = len_ent + len_name + len_aliases;
146   cp->h_addr_list = (char **) &(((char *) cp) [pos]);
147   pos += num_addr_list * sizeof (char *);
148   for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
149     if (*sp)
150       {
151         cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
152         memcpy (cp->h_addr_list [i], *sp, hp->h_length);
153         pos += align (hp->h_length, ALIGNMENT);
154       }
155     else
156       cp->h_addr_list [i] = *sp;
157
158   return cp;
159 }
160
161 static int
162 is_hostname(const char *sp)
163 {
164   if (*sp == '\0' || *sp == '@')
165     return 0;
166
167   for (; *sp; sp++)
168     {
169       if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
170         return 0;
171       if (*sp == '\\' && sp[1])
172         sp++;
173     }
174
175   return 1;
176 }
177
178 int
179 matchhostname (const char *h1, const char *h2)
180 {
181   struct hostent *hp1, *hp2;
182   int status;
183
184   if (strcasecmp (h1, h2) == 0)
185     return 1;
186
187   if (!is_hostname (h1) || !is_hostname (h2))
188     return 0;
189
190   hp1 = gethostbyname (h1);
191   if (hp1 == NULL)
192     return 0;
193
194   hp1 = hostent_dup (hp1);
195
196   hp2 = gethostbyname (h2);
197   if (hp2)
198     {
199       if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
200         status = 1;
201       else
202         {
203           char **ap1, **ap2;
204
205           status = 0;
206           for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
207             for (ap2 = hp2->h_addr_list; *ap2; ap2++)
208               if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
209                 {
210                   status = 1;
211                   break;
212                 }
213         }
214     }
215   else
216     status = 0;
217
218   free (hp1);
219   return status;
220 }
221
222
223 /* Map IP to hostname, and then map back to addr to make sure it is a
224  * reliable hostname
225  */
226 struct hostent *
227 get_reliable_hostbyaddr(const char *addr, int len, int type)
228 {
229         struct hostent *hp = NULL;
230
231         struct hostent *reverse;
232         struct hostent *forward;
233         char **sp;
234
235         reverse = gethostbyaddr (addr, len, type);
236         if (!reverse)
237                 return NULL;
238
239         /* must make sure the hostent is authorative. */
240
241         reverse = hostent_dup (reverse);
242         forward = gethostbyname (reverse->h_name);
243
244         if (forward) {
245                 /* now make sure the "addr" is in the list */
246                 for (sp = forward->h_addr_list ; *sp ; sp++) {
247                         if (memcmp (*sp, addr, forward->h_length) == 0)
248                                 break;
249                 }
250
251                 if (*sp) {
252                         /* it's valid */
253                         hp = hostent_dup (forward);
254                 }
255                 else {
256                         /* it was a FAKE */
257                         xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse",
258                               reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
259                 }
260         }
261         else {
262                 /* never heard of it. misconfigured DNS? */
263                 xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist",
264                       reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
265         }
266
267         free (reverse);
268         return hp;
269 }
270
271
272 #ifdef TEST
273 void
274 print_host (struct hostent *hp)
275 {
276   char **sp;
277
278   if (hp)
279     {
280       printf ("official hostname: %s\n", hp->h_name);
281       printf ("aliases:\n");
282       for (sp = hp->h_aliases; *sp; sp++)
283         printf ("  %s\n", *sp);
284       printf ("IP addresses:\n");
285       for (sp = hp->h_addr_list; *sp; sp++)
286         printf ("  %s\n", inet_ntoa (*(struct in_addr *) *sp));
287     }
288   else
289     printf ("Not host information\n");
290 }
291
292 int
293 main (int argc, char **argv)
294 {
295   struct hostent *hp = gethostbyname (argv [1]);
296   struct hostent *cp;
297   struct in_addr addr;
298
299   print_host (hp);
300
301   if (hp)
302     {
303       cp = hostent_dup (hp);
304       print_host (cp);
305       free (cp);
306     }
307   printf ("127.0.0.1 == %s: %d\n", argv [1],
308           matchhostname ("127.0.0.1", argv [1]));
309   addr.s_addr = inet_addr(argv [2]);
310   printf ("%s\n", inet_ntoa (addr));
311   cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
312   print_host (cp);
313   return 0;
314 }
315 #endif