source: rtems/cpukit/libnetworking/libc/gethostnamadr.c @ 0444c031

4.10
Last change on this file since 0444c031 was 0444c031, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 14, 2012 at 3:46:04 PM

Avoid buffer overflow and misaligned memory access

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*-
2 * Copyright (c) 1994, Garrett Wollman
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#if HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <ctype.h>
37#include <errno.h>
38#include <string.h>
39#ifdef HAVE_STRINGS_H
40#include <strings.h>
41#endif
42#include <arpa/nameser.h>               /* XXX hack for _res */
43#include <resolv.h>                     /* XXX hack for _res */
44
45#define _PATH_HOSTCONF  "/etc/host.conf"
46
47enum service_type {
48  SERVICE_NONE = 0,
49  SERVICE_BIND,
50  SERVICE_HOSTS,
51  SERVICE_NIS };
52#define SERVICE_MAX     SERVICE_NIS
53
54static struct {
55  const char *name;
56  enum service_type type;
57} service_names[] = {
58  { "hosts", SERVICE_HOSTS },
59  { "/etc/hosts", SERVICE_HOSTS },
60  { "hosttable", SERVICE_HOSTS },
61  { "htable", SERVICE_HOSTS },
62  { "bind", SERVICE_BIND },
63  { "dns", SERVICE_BIND },
64  { "domain", SERVICE_BIND },
65  { "yp", SERVICE_NIS },
66  { "yellowpages", SERVICE_NIS },
67  { "nis", SERVICE_NIS },
68  { 0, SERVICE_NONE }
69};
70
71static enum service_type service_order[SERVICE_MAX + 1];
72static int service_done = 0;
73
74static enum service_type
75get_service_name(const char *name) {
76        int i;
77        for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
78                if(!strcasecmp(name, service_names[i].name)) {
79                        return service_names[i].type;
80                }
81        }
82        return SERVICE_NONE;
83}
84
85static void
86init_services(void)
87{
88        char *cp, *p, buf[BUFSIZ];
89        register int cc = 0;
90        FILE *fd;
91
92        if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
93                                /* make some assumptions */
94                service_order[0] = SERVICE_BIND;
95                service_order[1] = SERVICE_HOSTS;
96                service_order[2] = SERVICE_NONE;
97        } else {
98                while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
99                        if(buf[0] == '#')
100                                continue;
101
102                        p = buf;
103                        while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
104                                ;
105                        if (cp == NULL)
106                                continue;
107                        do {
108                                if (isalpha((unsigned char)cp[0])) {
109                                        service_order[cc] = get_service_name(cp);
110                                        if(service_order[cc] != SERVICE_NONE)
111                                                cc++;
112                                }
113                                while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
114                                        ;
115                        } while(cp != NULL && cc < SERVICE_MAX);
116                }
117                service_order[cc] = SERVICE_NONE;
118                fclose(fd);
119        }
120        service_done = 1;
121}
122
123struct hostent *
124gethostbyname(const char *name)
125{
126        struct hostent *hp;
127
128        if (_res.options & RES_USE_INET6) {             /* XXX */
129                hp = gethostbyname2(name, AF_INET6);    /* XXX */
130                if (hp)                                 /* XXX */
131                        return (hp);                    /* XXX */
132        }                                               /* XXX */
133        return (gethostbyname2(name, AF_INET));
134}
135
136struct hostent *
137gethostbyname2(const char *name, int type)
138{
139        struct hostent *hp = 0;
140        int nserv = 0;
141
142        if (!service_done)
143                init_services();
144
145        while (!hp) {
146                switch (service_order[nserv]) {
147                      case SERVICE_NONE:
148                        return NULL;
149                      case SERVICE_HOSTS:
150                        hp = _gethostbyhtname(name, type);
151                        break;
152                      case SERVICE_BIND:
153                        hp = _gethostbydnsname(name, type);
154                        break;
155                      case SERVICE_NIS:
156                        hp = _gethostbynisname(name, type);
157                        break;
158                }
159                nserv++;
160        }
161        return hp;
162}
163
164int gethostbyaddr_r(const void *addr, socklen_t len, int type,
165               struct hostent *ret, char *buf, size_t buflen,
166               struct hostent **result, int *h_errnop)
167{
168  #warning "implement a proper gethostbyaddr_r"
169 
170  *result = gethostbyaddr( addr, len, type );
171  if ( *result ) 
172    return 0;
173  return -1;
174}
175
176struct hostent *
177gethostbyaddr(const void *addr, socklen_t len, int type)
178{
179        struct hostent *hp = 0;
180        int nserv = 0;
181
182        if (!service_done)
183                init_services();
184
185        while (!hp) {
186                switch (service_order[nserv]) {
187                      case SERVICE_NONE:
188                        return 0;
189                      case SERVICE_HOSTS:
190                        hp = _gethostbyhtaddr(addr, len, type);
191                        break;
192                      case SERVICE_BIND:
193                        hp = _gethostbydnsaddr(addr, len, type);
194                        break;
195                      case SERVICE_NIS:
196                        hp = _gethostbynisaddr(addr, len, type);
197                        break;
198                }
199                nserv++;
200        }
201        return hp;
202}
203
204void
205sethostent(int stayopen)
206{
207        _sethosthtent(stayopen);
208        _sethostdnsent(stayopen);
209}
210
211void
212endhostent(void)
213{
214        _endhosthtent();
215        _endhostdnsent();
216}
217
218#ifdef _THREAD_SAFE
219
220/* return length of decoded data or -1 */
221static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
222         unsigned int maxlen,unsigned char* behindpacket) {
223  unsigned char *tmp;
224  unsigned char *max=dest+maxlen;
225  unsigned char *after=packet+offset;
226  int ok=0;
227  for (tmp=after; maxlen>0&&*tmp; ) {
228    if (tmp>=behindpacket) return -1;
229    if ((*tmp>>6)==3) {   /* goofy DNS decompression */
230      unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
231      if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
232      if (after<tmp+2) after=tmp+2;
233      tmp=packet+ofs;
234      ok=0;
235    } else {
236      unsigned int duh;
237      if (dest+*tmp+1>max) return -1;
238      if (tmp+*tmp+1>=behindpacket) return -1;
239      for (duh=*tmp; duh>0; --duh)
240  *dest++=*++tmp;
241      *dest++='.'; ok=1;
242      ++tmp;
243      if (tmp>after) { after=tmp; if (!*tmp) ++after; }
244    }
245  }
246  if (ok) --dest;
247  *dest=0;
248  return after-packet;
249}
250
251static int __dns_gethostbyx_r(
252    const char* name, 
253    struct hostent* result,
254    char *buf, size_t buflen,
255    struct hostent **RESULT, 
256    int *h_errnop, 
257    int lookfor) 
258{
259
260  int names,ips;
261  unsigned char *cur;
262  unsigned char *max;
263  unsigned char inpkg[1500];
264  char* tmp;
265  int size;
266
267  if (lookfor==1) {
268    result->h_addrtype=AF_INET;
269    result->h_length=4;
270  } else {
271    result->h_addrtype=AF_INET6;
272    result->h_length=16;
273  }
274  result->h_aliases=(char**)(buf+8*sizeof(char*));
275  result->h_addr_list=(char**)buf;
276  result->h_aliases[0]=0;
277
278  cur=(unsigned char*)buf+16*sizeof(char*);
279  max=(unsigned char*)buf+buflen;
280  names=ips=0;
281
282  if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) {
283invalidpacket:
284    *h_errnop=HOST_NOT_FOUND;
285    return -1;
286  }
287  {
288    tmp=(char*)inpkg+12;
289    {
290      char Name[257];
291      unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
292      while (q>0) {
293  if (tmp>(char*)inpkg+size) goto invalidpacket;
294  while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
295  tmp+=5;
296  --q;
297      }
298      if (tmp>(char*)inpkg+size) goto invalidpacket;
299      q=((unsigned short)inpkg[6]<<8)+inpkg[7];
300      if (q<1) goto nodata;
301      while (q>0) {
302        int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
303  if (decofs<0) break;
304  tmp=(char*)inpkg+decofs;
305  --q;
306  if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
307      tmp[2]!=0 || tmp[3]!=1) {   /* CLASS != IN */
308    if (tmp[1]==5) {  /* CNAME */
309      tmp+=10;
310      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
311      if (decofs<0) break;
312      tmp=(char*)inpkg+decofs;
313    } else
314      break;
315    continue;
316  }
317  tmp+=10;  /* skip type, class, TTL and length */
318  {
319    int slen;
320    if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
321      slen=strlen(Name);
322      if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
323    } else if (lookfor==12) /* PTR */ {
324      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
325      if (decofs<0) break;
326      tmp=(char*)inpkg+decofs;
327      slen=strlen(Name);
328    } else
329      slen=strlen(Name);
330    strcpy((char*)cur,Name);
331    if (names==0)
332      result->h_name=(char*)cur;
333    else
334      result->h_aliases[names-1]=(char*)cur;
335    result->h_aliases[names]=0;
336    if (names<8) ++names;
337/*    cur+=slen+1; */
338    cur+=(slen|3)+1;
339    result->h_addr_list[ips++] = (char*)cur;
340    if (lookfor==1) /* A */ {
341      *(int*)cur=*(int*)tmp;
342      cur+=4;
343      result->h_addr_list[ips]=0;
344    } else if (lookfor==28) /* AAAA */ {
345      {
346        int k;
347        for (k=0; k<16; ++k) cur[k]=tmp[k];
348      }
349      cur+=16;
350      result->h_addr_list[ips]=0;
351    }
352  }
353/*        puts(Name); */
354      }
355    }
356  }
357  if (!names) {
358nodata:
359    *h_errnop=NO_DATA;
360    return -1;
361  }
362  *h_errnop=0;
363  *RESULT=result;
364  return 0;
365}
366
367
368
369
370int gethostbyname_r(const char*      name, 
371        struct hostent*  result,
372        char            *buf, 
373        int              buflen,
374        struct hostent **RESULT, 
375        int             *h_errnop) 
376{
377  uintptr_t current = (uintptr_t) buf;
378  uintptr_t end = current + buflen;
379  size_t L=strlen(name);
380
381  *RESULT = NULL;
382  *h_errnop = 0;
383
384  result->h_name = (char *) current;
385  current += L + 1;
386  if (current > end) { *h_errnop = ERANGE; return 1; }
387  strcpy(result->h_name, name);
388
389  current += sizeof(char **);
390  current -= current & (sizeof(char **) - 1);
391  result->h_addr_list = (char **) current;
392  current += 2 * sizeof(char **);
393  result->h_aliases = (char **) current;
394  current += sizeof(char **);
395  if (current > end) { *h_errnop = ERANGE; return 1; }
396  result->h_addr_list [0]= (char *) current;
397  current += 16;
398  result->h_addr_list [1] = NULL;
399  result->h_aliases [0] = NULL;
400  if (current > end) { *h_errnop = ERANGE; return 1; }
401  if (inet_pton(AF_INET,name,result->h_addr_list[0])) {
402    result->h_addrtype=AF_INET;
403    result->h_length=4;
404    *RESULT=result;
405    return 0;
406  } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) {
407    result->h_addrtype=AF_INET6;
408    result->h_length=16;
409    *RESULT=result;
410    return 0;
411  }
412
413
414  {
415    struct hostent* r;
416    sethostent(0);
417    while ((r=gethostent_r(buf,buflen))) {
418      int i;
419      if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) {  /* found it! */
420found:
421  memmove(result,r,sizeof(struct hostent));
422  *RESULT=result;
423  endhostent();
424  return 0;
425      }
426      for (i=0; i<16; ++i) {
427  if (r->h_aliases[i]) {
428    if (!strcasecmp(r->h_aliases[i],name)) goto found;
429  } else break;
430      }
431    }
432    endhostent();
433  }
434
435  return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1);
436}
437
438#endif
439
Note: See TracBrowser for help on using the repository browser.