Initial revision
[nfs-utils.git] / support / export / hostname.c
1 /*
2  * support/export/hostname.c
3  *
4  * Functions for hostname.
5  *
6  */
7
8 #include "config.h"
9
10 /*
11 #define TEST
12 */
13
14 #include <string.h>
15 #include <netdb.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <stdlib.h>
19 #ifdef TEST
20 #define xmalloc malloc
21 #else
22 #include "xmalloc.h"
23 #include "misc.h"
24 #endif
25
26 #define ALIGNMENT       sizeof (char *)
27
28 static int
29 align (int len, int al)
30 {
31   int i;
32   i = len % al;
33   if (i)
34     len += al - i;
35   return len;
36 }
37
38 struct hostent *
39 get_hostent (const char *addr, int len, int type)
40 {
41   struct hostent *cp;
42   int len_ent;
43   const char *name;
44   int len_name;
45   int num_aliases = 1;
46   int len_aliases = sizeof (char *);
47   int num_addr_list = 1;
48   int len_addr_list = sizeof (char *);
49   int pos;
50   struct in_addr *ipv4;
51
52   switch (type)
53     {
54     case AF_INET:
55       ipv4 = (struct in_addr *) addr;
56       name = inet_ntoa (*ipv4);
57       break;
58
59     default:
60       return NULL;
61     }
62
63   len_ent = align (sizeof (*cp), ALIGNMENT);
64   len_name = align (strlen (name) + 1, ALIGNMENT);
65
66   num_addr_list++;
67   len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
68
69   cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
70                                    + len_addr_list);
71
72   cp->h_addrtype = type;
73   cp->h_length = len;
74   pos = len_ent;
75   cp->h_name = (char *) &(((char *) cp) [pos]);
76   strcpy (cp->h_name, name);
77
78   pos += len_name;
79   cp->h_aliases = (char **) &(((char *) cp) [pos]);
80   pos += num_aliases * sizeof (char *);
81   cp->h_aliases [0] = NULL;
82
83   pos = len_ent + len_name + len_aliases;
84   cp->h_addr_list = (char **) &(((char *) cp) [pos]);
85   pos += num_addr_list * sizeof (char *);
86   cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
87   memcpy (cp->h_addr_list [0], addr, cp->h_length);
88   pos += align (cp->h_length, ALIGNMENT);
89   cp->h_addr_list [1] = NULL;
90
91   return cp;
92 }
93
94 struct hostent *
95 hostent_dup (struct hostent *hp)
96 {
97   int len_ent = align (sizeof (*hp), ALIGNMENT);
98   int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
99   int num_aliases = 1;
100   int len_aliases = sizeof (char *);
101   int num_addr_list = 1;
102   int len_addr_list = sizeof (char *);
103   int pos, i;
104   char **sp;
105   struct hostent *cp;
106
107   for (sp = hp->h_aliases; *sp; sp++)
108     {
109       num_aliases++;
110       len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
111                      + sizeof (char *);
112     }
113
114   for (sp = hp->h_addr_list; *sp; sp++)
115     {
116       num_addr_list++;
117       len_addr_list += align (hp->h_length, ALIGNMENT)
118                        + sizeof (char *);
119     }
120   
121   cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
122                                    + len_addr_list);
123
124   *cp = *hp;
125   pos = len_ent;
126   cp->h_name = (char *) &(((char *) cp) [pos]);
127   strcpy (cp->h_name, hp->h_name);
128
129   pos += len_name;
130   cp->h_aliases = (char **) &(((char *) cp) [pos]);
131   pos += num_aliases * sizeof (char *);
132   for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
133     if (*sp)
134       {
135         cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
136         strcpy (cp->h_aliases [i], *sp);
137         pos += align (strlen (*sp) + 1, ALIGNMENT);
138       }
139     else
140       cp->h_aliases [i] = *sp;
141
142   pos = len_ent + len_name + len_aliases;
143   cp->h_addr_list = (char **) &(((char *) cp) [pos]);
144   pos += num_addr_list * sizeof (char *);
145   for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
146     if (*sp)
147       {
148         cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
149         memcpy (cp->h_addr_list [i], *sp, hp->h_length);
150         pos += align (hp->h_length, ALIGNMENT);
151       }
152     else
153       cp->h_addr_list [i] = *sp;
154
155   return cp;
156 }
157
158 static int
159 is_hostname(const char *sp)
160 {
161   if (*sp == '\0' || *sp == '@')
162     return 0;
163
164   for (; *sp; sp++)
165     {
166       if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
167         return 0;
168       if (*sp == '\\' && sp[1])
169         sp++;
170     }
171
172   return 1;
173 }
174
175 int
176 matchhostname (const char *h1, const char *h2)
177 {
178   struct hostent *hp1, *hp2;
179   int status;
180
181   if (strcasecmp (h1, h2) == 0)
182     return 1;
183
184   if (!is_hostname (h1) || !is_hostname (h2))
185     return 0;
186
187   hp1 = gethostbyname (h1);
188   if (hp1 == NULL)
189     return 0;
190
191   hp1 = hostent_dup (hp1);
192
193   hp2 = gethostbyname (h2);
194   if (hp2)
195     {
196       if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
197         status = 1;
198       else
199         {
200           char **ap1, **ap2;
201
202           status = 0;
203           for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
204             for (ap2 = hp2->h_addr_list; *ap2; ap2++)
205               if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
206                 {
207                   status = 1;
208                   break;
209                 }
210         }
211     }
212   else
213     status = 0;
214
215   free (hp1);
216   return status;
217 }
218
219 #ifdef TEST
220 void
221 print_host (struct hostent *hp)
222 {
223   char **sp;
224
225   if (hp)
226     {
227       printf ("official hostname: %s\n", hp->h_name); 
228       printf ("aliases:\n");
229       for (sp = hp->h_aliases; *sp; sp++)
230         printf ("  %s\n", *sp);
231       printf ("IP addresses:\n");
232       for (sp = hp->h_addr_list; *sp; sp++)
233         printf ("  %s\n", inet_ntoa (*(struct in_addr *) *sp));
234     }
235   else
236     printf ("Not host information\n");
237 }
238
239 int
240 main (int argc, char **argv)
241 {
242   struct hostent *hp = gethostbyname (argv [1]);
243   struct hostent *cp;
244   struct in_addr addr;
245
246   print_host (hp);
247
248   if (hp)
249     {
250       cp = hostent_dup (hp);
251       print_host (cp);
252       free (cp);
253     }
254   printf ("127.0.0.1 == %s: %d\n", argv [1],
255           matchhostname ("127.0.0.1", argv [1]));
256   addr.s_addr = inet_addr(argv [2]);
257   printf ("%s\n", inet_ntoa (addr));
258   cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
259   print_host (cp);
260   return 0;
261 }
262 #endif