source: trunk/src/sh_static.c

Last change on this file was 570, checked in by katerina, 3 months ago

Fixes for some compile/cppcheck warnings, version 4.4.6.

File size: 50.1 KB
Line 
1/*  Copyright (C) 2003     Manuel Novoa III
2 *
3 *  This library is free software; you can redistribute it and/or
4 *  modify it under the terms of the GNU Library General Public
5 *  License as published by the Free Software Foundation; either
6 *  version 2 of the License, or (at your option) any later version.
7 *
8 *  This library is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 *  Library General Public License for more details.
12 *
13 *  You should have received a copy of the GNU Library General Public
14 *  License along with this library; if not, write to the Free
15 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18/*  Nov 6, 2003  Initial version.
19 *
20 *  NOTE: This implementation is quite strict about requiring all
21 *    field seperators.  It also does not allow leading whitespace
22 *    except when processing the numeric fields.  glibc is more
23 *    lenient.  See the various glibc difference comments below.
24 *
25 *  TODO:
26 *    Move to dynamic allocation of (currently staticly allocated)
27 *      buffers; especially for the group-related functions since
28 *      large group member lists will cause error returns.
29 *
30 */
31
32/* Jul 20, 2004 Adapted for samhain. Rainer Wichmann.
33 *
34 *   Stripped all unneeded code.
35 */
36
37#include "config_xor.h"
38
39#if defined(SH_COMPILE_STATIC) && defined(__linux__)
40
41#define _GNU_SOURCE
42#include <features.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <stdint.h>
46#include <string.h>
47#include <stddef.h>
48#include <errno.h>
49#include <assert.h>
50#include <ctype.h>
51#include <pwd.h>
52#include <grp.h>
53
54#include "sh_pthread.h"
55
56extern  int sl_close_fd (const char * file, int line, int fd);
57extern  int sl_fclose (const char * file, int line, FILE * fp);
58
59
60#ifndef _PATH_PASSWD
61#define _PATH_PASSWD "/etc/passwd"
62#endif
63#ifndef _PATH_GROUP
64#define _PATH_GROUP "/etc/group"
65#endif
66
67#undef  FIL__
68#define FIL__  _("sh_static.c")
69
70extern  int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz);
71extern  int sl_strlcat(char * dst, /*@null@*/const char * src, size_t siz);
72
73
74/**********************************************************************/
75/* Sizes for staticly allocated buffers. */
76
77#define PWD_BUFFER_SIZE 256
78#define GRP_BUFFER_SIZE 3584
79#define GRP_BUFFER_SIZE_MALLOC 32768
80
81/**********************************************************************/
82/* Prototypes for internal functions. */
83
84static int __parsepwent(void *pw, char *line);
85static int __parsegrent(void *gr, char *line);
86
87static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
88                       char *__restrict line_buff, 
89                       size_t buflen, FILE *f);
90
91#undef  GETXXKEY_R_FUNC
92#undef  GETXXKEY_R_PARSER
93#undef  GETXXKEY_R_ENTTYPE
94#undef  GETXXKEY_R_TEST
95#undef  DO_GETXXKEY_R_KEYTYPE
96#undef  DO_GETXXKEY_R_PATHNAME
97#define GETXXKEY_R_FUNC                 sh_getpwnam_r
98#define GETXXKEY_R_PARSER       __parsepwent
99#define GETXXKEY_R_ENTTYPE              struct passwd
100#define GETXXKEY_R_TEST(ENT)    (!strcmp((ENT)->pw_name, key))
101#define DO_GETXXKEY_R_KEYTYPE   const char *__restrict
102#define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
103
104int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
105                    GETXXKEY_R_ENTTYPE *__restrict resultbuf,
106                    char *__restrict buffer, size_t buflen,
107                    GETXXKEY_R_ENTTYPE **__restrict result)
108{
109  FILE *stream;
110  int rv;
111 
112  *result = NULL;
113 
114  if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
115    rv = errno;
116  } else {
117    /* __STDIO_SET_USER_LOCKING(stream); */
118    do {
119      if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
120                             buffer, buflen, stream))
121          ) {
122        if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
123          *result = resultbuf;
124          break;
125        }
126      } else {
127        if (rv == ENOENT) {     /* end-of-file encountered. */
128          rv = 0;
129        }
130        break;
131      }
132    } while (1);
133    sl_fclose(FIL__, __LINE__, stream);
134  }
135 
136  return rv;
137}
138
139#undef  GETXXKEY_R_FUNC
140#undef  GETXXKEY_R_PARSER
141#undef  GETXXKEY_R_ENTTYPE
142#undef  GETXXKEY_R_TEST
143#undef  DO_GETXXKEY_R_KEYTYPE
144#undef  DO_GETXXKEY_R_PATHNAME
145#define GETXXKEY_R_FUNC                 sh_getgrnam_r
146#define GETXXKEY_R_PARSER       __parsegrent
147#define GETXXKEY_R_ENTTYPE              struct group
148#define GETXXKEY_R_TEST(ENT)    (!strcmp((ENT)->gr_name, key))
149#define DO_GETXXKEY_R_KEYTYPE   const char *__restrict
150#define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
151
152int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
153                    GETXXKEY_R_ENTTYPE *__restrict resultbuf,
154                    char *__restrict buffer, size_t buflen,
155                    GETXXKEY_R_ENTTYPE **__restrict result)
156{
157  FILE *stream;
158  int rv;
159 
160  *result = NULL;
161 
162  if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
163    rv = errno;
164  } else {
165    /* __STDIO_SET_USER_LOCKING(stream); */
166    do {
167      if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
168                             buffer, buflen, stream))
169          ) {
170        if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
171          *result = resultbuf;
172          break;
173        }
174      } else {
175        if (rv == ENOENT) {     /* end-of-file encountered. */
176          rv = 0;
177        }
178        break;
179      }
180    } while (1);
181    sl_fclose(FIL__, __LINE__, stream);
182  }
183 
184  return rv;
185}
186
187#undef  GETXXKEY_R_FUNC
188#undef  GETXXKEY_R_PARSER
189#undef  GETXXKEY_R_ENTTYPE
190#undef  GETXXKEY_R_TEST
191#undef  DO_GETXXKEY_R_KEYTYPE
192#undef  DO_GETXXKEY_R_PATHNAME
193#define GETXXKEY_R_FUNC                 sh_getpwuid_r
194#define GETXXKEY_R_PARSER       __parsepwent
195#define GETXXKEY_R_ENTTYPE              struct passwd
196#define GETXXKEY_R_TEST(ENT)    ((ENT)->pw_uid == key)
197#define DO_GETXXKEY_R_KEYTYPE   uid_t
198#define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
199
200int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
201                    GETXXKEY_R_ENTTYPE *__restrict resultbuf,
202                    char *__restrict buffer, size_t buflen,
203                    GETXXKEY_R_ENTTYPE **__restrict result)
204{
205  FILE *stream;
206  int rv;
207 
208  *result = NULL;
209 
210  if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
211    rv = errno;
212  } else {
213    /* __STDIO_SET_USER_LOCKING(stream); */
214    do {
215      if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
216                             buffer, buflen, stream))
217          ) {
218        if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
219          *result = resultbuf;
220          break;
221        }
222      } else {
223        if (rv == ENOENT) {     /* end-of-file encountered. */
224          rv = 0;
225        }
226        break;
227      }
228    } while (1);
229    sl_fclose(FIL__, __LINE__, stream);
230  }
231 
232  return rv;
233}
234
235#undef  GETXXKEY_R_FUNC
236#undef  GETXXKEY_R_PARSER
237#undef  GETXXKEY_R_ENTTYPE
238#undef  GETXXKEY_R_TEST
239#undef  DO_GETXXKEY_R_KEYTYPE
240#undef  DO_GETXXKEY_R_PATHNAME
241#define GETXXKEY_R_FUNC                 sh_getgrgid_r
242#define GETXXKEY_R_PARSER       __parsegrent
243#define GETXXKEY_R_ENTTYPE              struct group
244#define GETXXKEY_R_TEST(ENT)    ((ENT)->gr_gid == key)
245#define DO_GETXXKEY_R_KEYTYPE   gid_t
246#define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
247
248int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
249                    GETXXKEY_R_ENTTYPE *__restrict resultbuf,
250                    char *__restrict buffer, size_t buflen,
251                    GETXXKEY_R_ENTTYPE **__restrict result)
252{
253  FILE *stream;
254  int rv;
255 
256  *result = NULL;
257 
258  if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
259    rv = errno;
260  } else {
261    /* __STDIO_SET_USER_LOCKING(stream); */
262    do {
263      if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
264                             buffer, buflen, stream))
265          ) {
266        if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
267          *result = resultbuf;
268          break;
269        }
270      } else {
271        if (rv == ENOENT) {     /* end-of-file encountered. */
272          rv = 0;
273        }
274        break;
275      }
276    } while (1);
277    sl_fclose(FIL__, __LINE__, stream);
278  }
279 
280  return rv;
281}
282
283struct passwd * sh_getpwuid(uid_t uid)
284{
285        static char buffer[PWD_BUFFER_SIZE];
286        static struct passwd resultbuf;
287        struct passwd *result;
288
289        sh_getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
290        return result;
291}
292
293struct passwd * getpwuid(uid_t uid)
294{
295        return sh_getpwuid(uid);
296}
297
298struct group * sh_getgrgid(gid_t gid)
299{
300        static char buffer[GRP_BUFFER_SIZE];
301        static struct group resultbuf;
302        struct group *result;
303
304        sh_getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
305        return result;
306}
307
308struct group * getgrgid(gid_t gid)
309{
310        return sh_getgrgid(gid);
311}
312
313struct passwd * sh_getpwnam(const char *name)
314{
315        static char buffer[PWD_BUFFER_SIZE];
316        static struct passwd resultbuf;
317        struct passwd *result;
318
319        sh_getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
320        return result;
321}
322
323struct group * sh_getgrnam(const char *name)
324{
325        static char buffer[GRP_BUFFER_SIZE];
326        static struct group resultbuf;
327        struct group *result;
328
329        sh_getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
330        return result;
331}
332
333SH_MUTEX_STATIC(pwf_lock, PTHREAD_MUTEX_INITIALIZER);
334
335
336static FILE *pwf = NULL;
337
338void  sh_setpwent(void)
339{
340        SH_MUTEX_LOCK(pwf_lock);
341        if (pwf) {
342                rewind(pwf);
343        }
344        SH_MUTEX_UNLOCK(pwf_lock);
345}
346
347void  sh_endpwent(void)
348{
349        SH_MUTEX_LOCK(pwf_lock);
350        if (pwf) {
351                sl_fclose(FIL__, __LINE__, pwf);
352                pwf = NULL;
353        }
354        SH_MUTEX_UNLOCK(pwf_lock);
355}
356
357
358static int  sh_getpwent_r(struct passwd *__restrict resultbuf, 
359                          char *__restrict buffer, size_t buflen,
360                          struct passwd **__restrict result)
361{
362        int rv;
363
364        SH_MUTEX_LOCK(pwf_lock);
365
366        *result = NULL;                         /* In case of error... */
367
368        if (!pwf) {
369                if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
370                        rv = errno;
371                        goto ERR;
372                }
373                /* __STDIO_SET_USER_LOCKING(pwf); */
374        }
375
376        if (!(rv = __pgsreader(__parsepwent, resultbuf,
377                                                   buffer, buflen, pwf))) {
378                *result = resultbuf;
379        }
380
381 ERR:
382        ; /* 'label at end of compound statement' */
383        SH_MUTEX_UNLOCK(pwf_lock);
384
385        return rv;
386}
387
388SH_MUTEX_STATIC(grf_lock, PTHREAD_MUTEX_INITIALIZER);
389
390static FILE *grf = NULL;
391
392void  sh_setgrent(void)
393{
394        SH_MUTEX_LOCK(grf_lock);
395        if (grf) {
396                rewind(grf);
397        }
398        SH_MUTEX_UNLOCK(grf_lock);
399}
400
401void  sh_endgrent(void)
402{
403        SH_MUTEX_LOCK(grf_lock);
404        if (grf) {
405                sl_fclose(FIL__, __LINE__, grf);
406                grf = NULL;
407        }
408        SH_MUTEX_UNLOCK(grf_lock);
409}
410
411static int sh_getgrent_r(struct group *__restrict resultbuf,
412                         char *__restrict buffer, size_t buflen,
413                         struct group **__restrict result)
414{
415        int rv;
416
417        SH_MUTEX_LOCK(grf_lock);
418
419        *result = NULL;                         /* In case of error... */
420
421        if (!grf) {
422                if (!(grf = fopen(_PATH_GROUP, "r"))) {
423                        rv = errno;
424                        goto ERR;
425                }
426                /* __STDIO_SET_USER_LOCKING(grf); */
427        }
428
429        if (!(rv = __pgsreader(__parsegrent, resultbuf,
430                                                   buffer, buflen, grf))) {
431                *result = resultbuf;
432        }
433
434 ERR:
435        ; /* 'label at end of compound statement' */
436        SH_MUTEX_UNLOCK(grf_lock);
437
438        return rv;
439}
440
441
442struct passwd * sh_getpwent(void)
443{
444        static char line_buff[PWD_BUFFER_SIZE];
445        static struct passwd pwd;
446        struct passwd *result;
447
448        sh_getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
449        return result;
450}
451
452
453struct group * sh_getgrent(void)
454{
455        static char line_buff[GRP_BUFFER_SIZE];
456        static struct group gr;
457        struct group *result;
458
459        sh_getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
460        return result;
461}
462
463int  sh_initgroups(const char *user, gid_t gid)
464{
465        FILE *grf;
466        gid_t *group_list = NULL;
467        size_t num_groups;
468        int rv;
469        char **m;
470        struct group group;
471
472        char * buff = calloc(1,GRP_BUFFER_SIZE_MALLOC);
473
474        rv = -1;
475
476        /* We alloc space for 8 gids at a time. */
477        if (buff && ((group_list = calloc(8,sizeof(gid_t *))) != NULL)
478                && ((grf = fopen(_PATH_GROUP, "r")) != NULL)
479                ) {
480
481          /* __STDIO_SET_USER_LOCKING(grf); */
482
483                *group_list = gid;
484                num_groups = 1;
485
486                while (!__pgsreader(__parsegrent, &group, buff, GRP_BUFFER_SIZE_MALLOC, grf)) {
487                        assert(group.gr_mem); /* Must have at least a NULL terminator. */
488                        if (group.gr_gid != gid) {
489                                for (m=group.gr_mem ; *m ; m++) {
490                                        if (!strcmp(*m, user)) {
491                                                if (!(num_groups & 7)) {
492                                                  gid_t *tmp = NULL;
493                                                  if (num_groups > (SIZE_MAX - 8)) {
494                                                    rv = -1;
495                                                    goto DO_CLOSE;
496                                                  }
497                                                  if ((num_groups+8) <= (SIZE_MAX / sizeof(gid_t *))) {
498                                                    tmp = (gid_t *)
499                                                      realloc(group_list,
500                                                              (num_groups+8) * sizeof(gid_t *));
501                                                  } 
502                                                  if (!tmp) {
503                                                    rv = -1;
504                                                    goto DO_CLOSE;
505                                                  }
506                                                  group_list = tmp;
507                                                }
508                                                group_list[num_groups++] = group.gr_gid;
509                                                break;
510                                        }
511                                }
512                        }
513                }
514
515                rv = setgroups(num_groups, group_list);
516        DO_CLOSE:
517                sl_fclose(FIL__, __LINE__, grf);
518        }
519
520        /* group_list will be NULL if initial malloc failed, which may trigger
521         * warnings from various malloc debuggers. */
522        if (group_list) free(group_list);
523        if (buff) free(buff);
524        /* cppcheck-suppress resourceLeak */
525        return rv;
526}
527
528
529/**********************************************************************/
530/* Internal uClibc functions.                                         */
531/**********************************************************************/
532
533static const unsigned char pw_off[] = {
534        offsetof(struct passwd, pw_name),       /* 0 */
535        offsetof(struct passwd, pw_passwd),     /* 1 */
536        offsetof(struct passwd, pw_uid),        /* 2 - not a char ptr */
537        offsetof(struct passwd, pw_gid),        /* 3 - not a char ptr */
538        offsetof(struct passwd, pw_gecos),      /* 4 */
539        offsetof(struct passwd, pw_dir),        /* 5 */
540        offsetof(struct passwd, pw_shell)       /* 6 */
541};
542
543static int __parsepwent(void *data, char *line)
544{
545        char *endptr;
546        char *p;
547        int i;
548
549        i = 0;
550        do {
551                p = ((char *) ((struct passwd *) data)) + pw_off[i];
552
553                if ((i & 6) ^ 2) {      /* i!=2 and i!=3 */
554                        *((char **) p) = line;
555                        if (i==6) {
556                                return 0;
557                        }
558                        /* NOTE: glibc difference - glibc allows omission of
559                         * ':' seperators after the gid field if all remaining
560                         * entries are empty.  We require all separators. */
561                        if (!(line = strchr(line, ':'))) {
562                                break;
563                        }
564                } else {
565                        unsigned long t = strtoul(line, &endptr, 10);
566                        /* Make sure we had at least one digit, and that the
567                         * failing char is the next field seperator ':'.  See
568                         * glibc difference note above. */
569                        /* TODO: Also check for leading whitespace? */
570                        if ((endptr == line) || (*endptr != ':')) {
571                                break;
572                        }
573                        line = endptr;
574                        if (i & 1) {            /* i == 3 -- gid */
575                                *((gid_t *) p) = t;
576                        } else {                        /* i == 2 -- uid */
577                                *((uid_t *) p) = t;
578                        }
579                }
580
581                *line++ = 0;
582                ++i;
583        } while (1);
584
585        return -1;
586}
587
588static const unsigned char gr_off[] = {
589        offsetof(struct group, gr_name),        /* 0 */
590        offsetof(struct group, gr_passwd),      /* 1 */
591        offsetof(struct group, gr_gid)          /* 2 - not a char ptr */
592};
593
594static int __parsegrent(void *data, char *line)
595{
596        char *endptr;
597        char *p;
598        int i;
599        char **members;
600        char *end_of_buf;
601
602        end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
603        i = 0;
604        do {
605                p = ((char *) ((struct group *) data)) + gr_off[i];
606
607                if (i < 2) {
608                        *((char **) p) = line;
609                        if (!(line = strchr(line, ':'))) {
610                                break;
611                        }
612                        *line++ = 0;
613                        ++i;
614                } else {
615                        *((gid_t *) p) = strtoul(line, &endptr, 10);
616
617                        /* NOTE: glibc difference - glibc allows omission of the
618                         * trailing colon when there is no member list.  We treat
619                         * this as an error. */
620
621                        /* Make sure we had at least one digit, and that the
622                         * failing char is the next field seperator ':'.  See
623                         * glibc difference note above. */
624                        if ((endptr == line) || (*endptr != ':')) {
625                                break;
626                        }
627
628                        i = 1;                          /* Count terminating NULL ptr. */
629                        p = endptr;
630
631                        if (p[1]) { /* We have a member list to process. */
632                                /* Overwrite the last ':' with a ',' before counting.
633                                 * This allows us to test for initial ',' and adds
634                                 * one ',' so that the ',' count equals the member
635                                 * count. */
636                                *p = ',';
637                                do {
638                                        /* NOTE: glibc difference - glibc allows and trims leading
639                                         * (but not trailing) space.  We treat this as an error. */
640                                        /* NOTE: glibc difference - glibc allows consecutive and
641                                         * trailing commas, and ignores "empty string" users.  We
642                                         * treat this as an error. */
643                                        if (*p == ',') {
644                                                ++i;
645                                                *p = 0; /* nul-terminate each member string. */
646                                                if (!*++p || (*p == ',') || isspace(*p)) {
647                                                        goto ERR;
648                                                }
649                                        }
650                                } while (*++p);
651                        }
652
653                        /* Now align (p+1), rounding up. */
654                        /* Assumes sizeof(char **) is a power of 2. */
655                        members = (char **)( (((intptr_t) p) + sizeof(char **))
656                                                                 & ~((intptr_t)(sizeof(char **) - 1)) );
657
658                        if (((char *)(members + i)) > end_of_buf) {     /* No space. */
659                                break;
660                        }
661
662                        ((struct group *) data)->gr_mem = members;
663
664                        if (--i) {
665                                p = endptr;     /* Pointing to char prior to first member. */
666                                do {
667                                        *members++ = ++p;
668                                        if (!--i) break;
669                                        while (*++p) {}
670                                } while (1);
671                        }                               
672                        *members = NULL;
673
674                        return 0;
675                }
676        } while (1);
677
678 ERR:
679        return -1;
680}
681
682/* Reads until if EOF, or until if finds a line which fits in the buffer
683 * and for which the parser function succeeds.
684 *
685 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
686 */
687
688static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
689                       char *__restrict line_buff, size_t buflen, FILE *f)
690{
691        size_t line_len; /* int -> size_t R.W. */
692        int skip;
693        int rv = ERANGE;
694
695        if (buflen < PWD_BUFFER_SIZE) {
696                errno = rv;
697        } else {
698          /* __STDIO_THREADLOCK(f); */
699
700                skip = 0;
701                do {
702                        if (!fgets(line_buff, buflen, f)) {
703                                if (feof(f)) {
704                                        rv = ENOENT;
705                                }
706                                break;
707                        }
708
709                        line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
710                        if (line_buff[line_len] == '\n') {
711                                line_buff[line_len] = 0;
712                        } else if (line_len + 2 == buflen) { /* line too long */
713                                rv = ERANGE;
714                                break;
715                                /*
716                                ++skip;
717                                continue;
718                                */
719                        }
720
721                        if (skip) {
722                                --skip;
723                                continue;
724                        }
725
726                        /* NOTE: glibc difference - glibc strips leading whitespace from
727                         * records.  We do not allow leading whitespace. */
728
729                        /* Skip empty lines, comment lines, and lines with leading
730                         * whitespace. */
731                        if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
732                                if (__parserfunc == __parsegrent) {     /* Do evil group hack. */
733                                        /* The group entry parsing function needs to know where
734                                         * the end of the buffer is so that it can construct the
735                                         * group member ptr table. */
736                                        ((struct group *) data)->gr_name = line_buff + buflen;
737                                }
738
739                                if (!__parserfunc(data, line_buff)) {
740                                        rv = 0;
741                                        break;
742                                }
743                        }
744                } while (1);
745
746                /* __STDIO_THREADUNLOCK(f); */
747        }
748
749        return rv;
750}
751
752/* resolv.c: DNS Resolver
753 *
754 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
755 *                     The Silver Hammer Group, Ltd.
756 *
757 * This library is free software; you can redistribute it and/or
758 * modify it under the terms of the GNU Library General Public
759 * License as published by the Free Software Foundation; either
760 * version 2 of the License, or (at your option) any later version.
761*/
762
763/*
764 * Portions Copyright (c) 1985, 1993
765 *    The Regents of the University of California.  All rights reserved.
766 *
767 * Redistribution and use in source and binary forms, with or without
768 * modification, are permitted provided that the following conditions
769 * are met:
770 * 1. Redistributions of source code must retain the above copyright
771 *    notice, this list of conditions and the following disclaimer.
772 * 2. Redistributions in binary form must reproduce the above copyright
773 *    notice, this list of conditions and the following disclaimer in the
774 *    documentation and/or other materials provided with the distribution.
775 * 4. Neither the name of the University nor the names of its contributors
776 *    may be used to endorse or promote products derived from this software
777 *    without specific prior written permission.
778 *
779 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
780 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
781 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
782 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
783 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
784 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
785 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
786 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
787 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
788 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
789 * SUCH DAMAGE.
790 */
791
792/*
793 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
794 *
795 * Permission to use, copy, modify, and distribute this software for any
796 * purpose with or without fee is hereby granted, provided that the above
797 * copyright notice and this permission notice appear in all copies, and that
798 * the name of Digital Equipment Corporation not be used in advertising or
799 * publicity pertaining to distribution of the document or software without
800 * specific, written prior permission.
801 *
802 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
803 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
804 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
805 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
806 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
807 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
808 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
809 * SOFTWARE.
810 */
811
812/*
813 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
814 *
815 * Permission to use, copy, modify, and distribute this software for any
816 * purpose with or without fee is hereby granted, provided that the above
817 * copyright notice and this permission notice appear in all copies.
818 *
819 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
820 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
821 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
822 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
823 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
824 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
825 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
826 * SOFTWARE.
827 */
828
829/*
830 *
831 *  5-Oct-2000 W. Greathouse  wgreathouse@smva.com
832 *                              Fix memory leak and memory corruption.
833 *                              -- Every name resolution resulted in
834 *                                 a new parse of resolv.conf and new
835 *                                 copy of nameservers allocated by
836 *                                 strdup.
837 *                              -- Every name resolution resulted in
838 *                                 a new read of resolv.conf without
839 *                                 resetting index from prior read...
840 *                                 resulting in exceeding array bounds.
841 *
842 *                              Limit nameservers read from resolv.conf
843 *
844 *                              Add "search" domains from resolv.conf
845 *
846 *                              Some systems will return a security
847 *                              signature along with query answer for
848 *                              dynamic DNS entries.
849 *                              -- skip/ignore this answer
850 *
851 *                              Include arpa/nameser.h for defines.
852 *
853 *                              General cleanup
854 *
855 * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
856 *   partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
857 *   functions added), IPv6 nameservers are also supported.
858 *
859 * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
860 *   more IPv6 support (IPv6 support for gethostbyaddr();
861 *   address family parameter and improved IPv6 support for get_hosts_byname
862 *   and read_etc_hosts; getnameinfo() port from glibc; defined
863 *   defined ip6addr_any and in6addr_loopback)
864 *
865 * 2-Feb-2002 Erik Andersen <andersee@debian.org>
866 * Added gethostent(), sethostent(), and endhostent()
867 *
868 * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
869 *   Fixed __read_etc_hosts_r to return alias list, and modified buffer
870 *   allocation accordingly.  See MAX_ALIASES and ALIAS_DIM below.
871 *   This fixes the segfault in the Python 2.2.1 socket test.
872 *
873 * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
874 *   Fixed __decode_dotted to count the terminating null character
875 *   in a host name.
876 *
877 * 02-Oct-2003 Tony J. White <tjw@tjw.org>
878 *   Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
879 *   and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
880 *   and openldap.
881 *
882 */
883
884#include <sys/socket.h>
885#include <netinet/in.h>
886#include <arpa/inet.h>
887
888/* sl_close_fd(FIL__, __LINE__, )
889 */
890#include <unistd.h>
891
892/* 'struct hostent'
893 */
894#include <netdb.h>
895
896/* constanst like HFIXEDSZ
897 */
898#include <arpa/nameser.h>
899
900SH_MUTEX_STATIC(resolv_lock, PTHREAD_MUTEX_INITIALIZER);
901
902#define __UCLIBC_HAS_IPV6__
903#define MAX_RECURSE 5
904#define REPLY_TIMEOUT 10
905#define MAX_RETRIES 3
906#define MAX_SERVERS 3
907#define MAX_SEARCH 4
908#define MAX_ALIASES     5
909
910/* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
911#define         ALIAS_DIM               (2 + MAX_ALIASES + 1)
912
913static int __nameservers;
914static char * __nameserver[MAX_SERVERS];
915static int __searchdomains;
916static char * __searchdomain[MAX_SEARCH];
917
918#undef DEBUG
919/* #define DEBUG */
920
921#ifdef DEBUG
922/* flawfinder: ignore *//* definition of debug macro */
923#define DPRINTF(X,args...) fprintf(stderr, X, ##args)
924#else
925#define DPRINTF(X,args...)
926#endif /* DEBUG */
927
928struct resolv_header {
929        int id;
930        int qr,opcode,aa,tc,rd,ra,rcode;
931        int qdcount;
932        int ancount;
933        int nscount;
934        int arcount;
935};
936
937struct resolv_question {
938        char * dotted;
939        int qtype;
940        int qclass;
941};
942
943struct resolv_answer {
944        char * dotted;
945        int atype;
946        int aclass;
947        int ttl;
948        int rdlength;
949        unsigned char * rdata;
950        int rdoffset;
951};
952
953enum etc_hosts_action {
954    GET_HOSTS_BYNAME = 0,
955    GETHOSTENT,
956    GET_HOSTS_BYADDR,
957};
958
959static int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
960{
961        if (maxlen < HFIXEDSZ)
962                return -1;
963
964        dest[0] = (h->id & 0xff00) >> 8;
965        dest[1] = (h->id & 0x00ff) >> 0;
966        dest[2] = (h->qr ? 0x80 : 0) |
967                ((h->opcode & 0x0f) << 3) |
968                (h->aa ? 0x04 : 0) | 
969                (h->tc ? 0x02 : 0) | 
970                (h->rd ? 0x01 : 0);
971        dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
972        dest[4] = (h->qdcount & 0xff00) >> 8;
973        dest[5] = (h->qdcount & 0x00ff) >> 0;
974        dest[6] = (h->ancount & 0xff00) >> 8;
975        dest[7] = (h->ancount & 0x00ff) >> 0;
976        dest[8] = (h->nscount & 0xff00) >> 8;
977        dest[9] = (h->nscount & 0x00ff) >> 0;
978        dest[10] = (h->arcount & 0xff00) >> 8;
979        dest[11] = (h->arcount & 0x00ff) >> 0;
980
981        return HFIXEDSZ;
982}
983
984static int __decode_header(unsigned char *data, struct resolv_header *h)
985{
986        h->id = (data[0] << 8) | data[1];
987        h->qr = (data[2] & 0x80) ? 1 : 0;
988        h->opcode = (data[2] >> 3) & 0x0f;
989        h->aa = (data[2] & 0x04) ? 1 : 0;
990        h->tc = (data[2] & 0x02) ? 1 : 0;
991        h->rd = (data[2] & 0x01) ? 1 : 0;
992        h->ra = (data[3] & 0x80) ? 1 : 0;
993        h->rcode = data[3] & 0x0f;
994        h->qdcount = (data[4] << 8) | data[5];
995        h->ancount = (data[6] << 8) | data[7];
996        h->nscount = (data[8] << 8) | data[9];
997        h->arcount = (data[10] << 8) | data[11];
998
999        return HFIXEDSZ;
1000}
1001
1002static int __length_dotted(const unsigned char *data, int offset)
1003{
1004        int orig_offset = offset;
1005        int l;
1006
1007        if (!data)
1008                return -1;
1009
1010        do {
1011                l = data[offset];
1012                if (offset < INT_MAX)
1013                        offset++;
1014                else
1015                        return -1;
1016                if (!l)
1017                  break;
1018               
1019                DPRINTF("l[%d] = %d\n", offset, l);
1020
1021                if ((l & 0xc0) == (0xc0)) {
1022                        if (offset < INT_MAX)
1023                          offset++;
1024                        else
1025                          return -1;
1026                        break;
1027                }
1028
1029                if (offset <= (INT_MAX - l))
1030                  offset += l;
1031                else
1032                  return -1;
1033
1034        } while (l);
1035
1036        DPRINTF("orig: %d now %d\n", orig_offset, offset);
1037        return offset - orig_offset;
1038}
1039
1040static int __length_question(unsigned char *message, int offset)
1041{
1042        int i;
1043
1044        i = __length_dotted(message, offset);
1045        if (i < 0)
1046                return i;
1047        if (i < (INT_MAX - 4))
1048          return i + 4;
1049        else
1050          return -1;
1051}
1052
1053/* Decode a dotted string from nameserver transport-level encoding.
1054   This routine understands compressed data. */
1055
1056static int __decode_dotted(const unsigned char *data, int offset,
1057                                  char *dest, int maxlen)
1058{
1059        int l;
1060        int measure = 1;
1061        int total = 0;
1062        int used = 0;
1063
1064        if (!data)
1065                return -1;
1066        if ((offset < 0) || (offset > (PACKETSZ-1)))
1067                return -1;
1068        while ((l=data[offset])) {
1069                if (offset < (PACKETSZ-1)) offset++;
1070                else return -1;
1071                if (measure)
1072                    { if (total < INT_MAX) total++; else return -1; }
1073                if ((l & 0xc0) == (0xc0)) {
1074                        if (measure)
1075                          { if (total < INT_MAX) total++; else return -1; }
1076                        /* compressed item, redirect */ 
1077                        offset = ((l & 0x3f) << 8) | data[offset];
1078                        if ((offset < 0) || (offset > (PACKETSZ-1)))
1079                          return -1; 
1080                        measure = 0;
1081                        continue;
1082                }
1083               
1084                if (used >= (INT_MAX - l))
1085                  return -1;
1086
1087                if ((used + l + 1) >= maxlen)
1088                  return -1; 
1089
1090                memcpy(dest + used, data + offset, l);
1091               
1092                if (offset <= ((PACKETSZ-1) - l))
1093                  offset += l;
1094                else
1095                  return -1;
1096
1097                if (used <= (INT_MAX - l))
1098                  used += l;
1099                else
1100                  return -1;
1101                if (measure)
1102                  { if (total <= (INT_MAX -l)) total += l; else return -1; }
1103
1104                if (used >= maxlen)
1105                  return -1;
1106                if (data[offset] != 0)
1107                        dest[used++] = '.';
1108                else
1109                        dest[used++] = '\0';
1110        }
1111
1112        /* The null byte must be counted too */
1113        if (measure) {
1114            if (total < INT_MAX) total++; else return -1; 
1115        }
1116
1117        DPRINTF("Total decode len = %d\n", total);
1118
1119        return total;
1120}
1121
1122static int __decode_answer(unsigned char *message, int offset,
1123                                  struct resolv_answer *a)
1124{
1125        char temp[256];
1126        int i = 0;
1127
1128        i = __decode_dotted(message, offset, temp, sizeof(temp));
1129        if (i < 0 || i > PACKETSZ)
1130                return -1;
1131
1132        if (offset <= ((PACKETSZ - 10) - i))
1133          message += offset + i;
1134        else
1135          return -1;
1136
1137        a->dotted = strdup(temp);
1138        a->atype = (message[0] << 8) | message[1];
1139        message += 2;
1140        a->aclass = (message[0] << 8) | message[1];
1141        message += 2;
1142        a->ttl = (message[0] << 24) |
1143                (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1144        message += 4;
1145        a->rdlength = (message[0] << 8) | message[1];
1146        message += 2;
1147        a->rdata = message;
1148        a->rdoffset = offset + i + RRFIXEDSZ;
1149
1150        DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1151
1152        if (RRFIXEDSZ <= (INT_MAX - i))
1153          i += RRFIXEDSZ;
1154        else
1155          return -1;
1156        if (a->rdlength <= (INT_MAX - i))
1157          return i + a->rdlength;
1158        else
1159          return -1;
1160}
1161
1162
1163/* Encode a dotted string into nameserver transport-level encoding.
1164   This routine is fairly dumb, and doesn't attempt to compress
1165   the data */
1166
1167static int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
1168{
1169        unsigned int used = 0;
1170
1171        while (dotted && *dotted) {
1172                char *c = strchr(dotted, '.');
1173                unsigned int l = c ? (unsigned int)(c - dotted) : strlen(dotted);
1174
1175                if (l >= ((unsigned int)maxlen - used - 1))
1176                        return -1;
1177
1178                dest[used++] = l;
1179                memcpy(dest + used, dotted, l);
1180                used += l;
1181
1182                if (c)
1183                        dotted = c + 1;
1184                else
1185                        break;
1186        }
1187
1188        if (maxlen < 1)
1189                return -1;
1190
1191        dest[used++] = 0;
1192
1193        return used;
1194}
1195
1196static int __encode_question(struct resolv_question *q,
1197                                        unsigned char *dest, int maxlen)
1198{
1199        int i;
1200
1201        i = __encode_dotted(q->dotted, dest, maxlen);
1202        if (i < 0)
1203                return i;
1204
1205        dest += i;
1206        if (maxlen < i)
1207          return -1;
1208        maxlen -= i;
1209
1210        if (maxlen < 4)
1211                return -1;
1212
1213        dest[0] = (q->qtype & 0xff00) >> 8;
1214        dest[1] = (q->qtype & 0x00ff) >> 0;
1215        dest[2] = (q->qclass & 0xff00) >> 8;
1216        dest[3] = (q->qclass & 0x00ff) >> 0;
1217
1218        if (i <= (INT_MAX - 4))
1219          return i + 4;
1220        else
1221          return -1;
1222}
1223
1224
1225/* Just for the record, having to lock __dns_lookup() just for these two globals
1226 * is pretty lame.  I think these two variables can probably be de-global-ized,
1227 * which should eliminate the need for doing locking here...  Needs a closer
1228 * look anyways. */
1229static int ns=0, id=1;
1230
1231static int __dns_lookup(const char *name, int type, int nscount, char **nsip,
1232                           unsigned char **outpacket, struct resolv_answer *a)
1233{
1234        int i, j, len, fd, pos, rc;
1235        struct timeval tv;
1236        fd_set fds;
1237        struct resolv_header h;
1238        struct resolv_question q;
1239        int retries = 0;
1240        unsigned char * packet = calloc(1,PACKETSZ);
1241        char *dns, *lookup = calloc(1,MAXDNAME);
1242        int variant = 0;
1243        struct sockaddr_in sa;
1244#ifdef __UCLIBC_HAS_IPV6__
1245        int v6;
1246        struct sockaddr_in6 sa6;
1247#endif
1248
1249        fd = -1;
1250
1251        if (!packet || !lookup || !nscount)
1252            goto fail;
1253
1254        DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1255
1256        SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1257        ns %= nscount;
1258        SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1259
1260        while (retries++ < MAX_RETRIES) {
1261                if (fd != -1)
1262                        sl_close_fd(FIL__, __LINE__, fd);
1263
1264                memset(packet, 0, PACKETSZ);
1265
1266                memset(&h, 0, sizeof(h));
1267
1268                /* Mess with globals while under lock */
1269                SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1270                ++id;
1271                id &= 0xffff;
1272                h.id = id;
1273                dns = nsip[ns];
1274                SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1275
1276                h.qdcount = 1;
1277                h.rd = 1;
1278
1279                DPRINTF("encoding header %d\n", h.rd);
1280
1281                i = __encode_header(&h, packet, PACKETSZ);
1282                if (i < 0)
1283                        goto fail;
1284
1285                sl_strlcpy(lookup,name,MAXDNAME);
1286                SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1287                if (variant < __searchdomains && strchr(lookup, '.') == NULL)
1288                {
1289                    sl_strlcat(lookup,".", MAXDNAME);
1290                    sl_strlcat(lookup,__searchdomain[variant], MAXDNAME);
1291                }
1292                SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1293                DPRINTF("lookup name: %s\n", lookup);
1294                q.dotted = (char *)lookup;
1295                q.qtype = type;
1296                q.qclass = C_IN; /* CLASS_IN */
1297
1298                j = __encode_question(&q, packet+i, PACKETSZ-i);
1299                if (j < 0)
1300                        goto fail;
1301
1302                len = i + j;
1303
1304                DPRINTF("On try %d, sending query to port %d of machine %s\n",
1305                                retries, NAMESERVER_PORT, dns);
1306
1307#ifdef __UCLIBC_HAS_IPV6__
1308                v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0;
1309                fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1310#else
1311                fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1312#endif
1313                if (fd < 0) {
1314                    continue;
1315                }
1316
1317                /* Connect to the UDP socket so that asyncronous errors are returned */         
1318#ifdef __UCLIBC_HAS_IPV6__
1319                if (v6) {
1320                    sa6.sin6_family = AF_INET6;
1321                    sa6.sin6_port = htons(NAMESERVER_PORT);
1322                    /* sa6.sin6_addr is already here */
1323                    rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6));
1324                } else {
1325#endif
1326                    sa.sin_family = AF_INET;
1327                    sa.sin_port = htons(NAMESERVER_PORT);
1328                    sa.sin_addr.s_addr = inet_addr(dns);
1329                    rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
1330#ifdef __UCLIBC_HAS_IPV6__
1331                }
1332#endif
1333                if (rc < 0) {
1334                    if (errno == ENETUNREACH) {
1335                        /* routing error, presume not transient */
1336                        goto tryall;
1337                    } else
1338                        /* retry */
1339                        continue;
1340                }
1341
1342                DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
1343                                len, h.id, h.qr);
1344
1345                send(fd, packet, len, 0);
1346
1347                FD_ZERO(&fds);
1348                FD_SET(fd, &fds);
1349                tv.tv_sec = REPLY_TIMEOUT;
1350                tv.tv_usec = 0;
1351                if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1352                    DPRINTF("Timeout\n");
1353
1354                        /* timed out, so retry send and receive,
1355                         * to next nameserver on queue */
1356                        goto again;
1357                }
1358
1359                i = recv(fd, packet, 512, 0);
1360                if (i < HFIXEDSZ) {
1361                        /* too short ! */
1362                        goto again;
1363                }
1364
1365                /* ok because we have checked that recv at least HFIXEDSZ */
1366                __decode_header(packet, &h);
1367
1368                DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
1369
1370                SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1371                if ((h.id != id) || (!h.qr)) {
1372                        SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1373                        /* unsolicited */
1374                        goto again;
1375                }
1376                SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1377
1378
1379                DPRINTF("Got response %s\n", "(i think)!");
1380                DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1381                                h.qdcount, h.ancount, h.nscount, h.arcount);
1382                DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1383                                h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1384
1385                if ((h.rcode) || (h.ancount < 1)) {
1386                        /* negative result, not present */
1387                        goto again;
1388                }
1389
1390                pos = HFIXEDSZ;
1391
1392                for (j = 0; j < h.qdcount; j++) {
1393                        DPRINTF("Skipping question %d at %d\n", j, pos);
1394                        i = __length_question(packet, pos);
1395                        DPRINTF("Length of question %d is %d\n", j, i);
1396                        if (i < 0)
1397                                goto again;
1398                        pos += i;
1399                        if (pos >= PACKETSZ)
1400                                goto again;
1401                }
1402                DPRINTF("Decoding answer at pos %d\n", pos);
1403
1404                for (j=0;j<h.ancount;j++)
1405                {
1406                    i = __decode_answer(packet, pos, a);
1407
1408                    if (i<0) {
1409                        DPRINTF("failed decode %d\n", i);
1410                        goto again;
1411                    }
1412                    /* For all but T_SIG, accept first answer */
1413                    if (a->atype != T_SIG)
1414                        break;
1415
1416                    DPRINTF("skipping T_SIG %d\n", i);
1417                    free(a->dotted);
1418                    pos += i;
1419                    if (pos >= PACKETSZ)
1420                            goto again;
1421                }
1422
1423                DPRINTF("Answer name = |%s|\n", a->dotted);
1424                DPRINTF("Answer type = |%d|\n", a->atype);
1425
1426                sl_close_fd(FIL__, __LINE__, fd);
1427
1428                if (outpacket)
1429                        *outpacket = packet;
1430                else
1431                        free(packet);
1432                free(lookup);
1433                return (0);                             /* success! */
1434
1435          tryall:
1436                /* if there are other nameservers, give them a go,
1437                   otherwise return with error */
1438                {
1439                    int sdomains;
1440
1441                    SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1442                    sdomains=__searchdomains;
1443                    SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1444                    variant = 0;
1445                    if (retries >= nscount*(sdomains+1))
1446                        goto fail;
1447                }
1448
1449          again:
1450                /* if there are searchdomains, try them or fallback as passed */
1451                {
1452                    int sdomains;
1453                    SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1454                    sdomains=__searchdomains;
1455                    SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1456
1457                    if (variant < sdomains) {
1458                        /* next search */
1459                        variant++;
1460                    } else {
1461                        /* next server, first search */
1462                        SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1463                        ns = (ns + 1) % nscount;
1464                        SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1465                        variant = 0;
1466                    }
1467                }
1468        }
1469
1470fail:
1471        if (fd != -1)
1472            sl_close_fd(FIL__, __LINE__, fd);
1473        if (lookup)
1474            free(lookup);
1475        if (packet)
1476            free(packet);
1477        return -1;
1478}
1479
1480static void __open_etc_hosts(FILE **fp)
1481{
1482        if ((*fp = fopen("/etc/hosts", "r")) == NULL) {
1483                *fp = fopen("/etc/config/hosts", "r");
1484        }
1485        /* cppcheck-suppress resourceLeak */
1486        return;
1487}
1488
1489static int __read_etc_hosts_r(FILE * fp, const char * name, int type,
1490                     enum etc_hosts_action action,
1491                     struct hostent * result_buf,
1492                     char * buf, size_t buflen,
1493                     struct hostent ** result,
1494                     int * h_errnop)
1495{
1496        struct in_addr  *in=NULL;
1497        struct in_addr  **addr_list=NULL;
1498#ifdef __UCLIBC_HAS_IPV6__
1499        struct in6_addr *in6=NULL;
1500        struct in6_addr **addr_list6=NULL;
1501#endif /* __UCLIBC_HAS_IPV6__ */
1502        char                                    *cp;
1503        char                                    **alias;
1504        int                                             aliases, i;
1505        int             ret=HOST_NOT_FOUND;
1506
1507        if (buflen < sizeof(char *)*(ALIAS_DIM))
1508                return ERANGE;
1509        alias=(char **)buf;
1510        buf+=sizeof(char **)*(ALIAS_DIM);
1511        buflen-=sizeof(char **)*(ALIAS_DIM);
1512
1513        if (action!=GETHOSTENT) {
1514#ifdef __UCLIBC_HAS_IPV6__
1515                char *p=buf;
1516                size_t len=buflen;
1517#endif /* __UCLIBC_HAS_IPV6__ */
1518                *h_errnop=NETDB_INTERNAL;
1519                if (buflen < sizeof(*in))
1520                        return ERANGE;
1521                in=(struct in_addr*)buf;
1522                buf+=sizeof(*in);
1523                buflen-=sizeof(*in);
1524
1525                if (buflen < sizeof(*addr_list)*2)
1526                        return ERANGE;
1527                addr_list=(struct in_addr **)buf;
1528                buf+=sizeof(*addr_list)*2;
1529                buflen-=sizeof(*addr_list)*2;
1530
1531#ifdef __UCLIBC_HAS_IPV6__
1532                if (len < sizeof(*in6))
1533                        return ERANGE;
1534                in6=(struct in6_addr*)p;
1535                p+=sizeof(*in6);
1536                len-=sizeof(*in6);
1537
1538                if (len < sizeof(*addr_list6)*2)
1539                        return ERANGE;
1540                addr_list6=(struct in6_addr**)p;
1541                p+=sizeof(*addr_list6)*2;
1542                len-=sizeof(*addr_list6)*2;
1543
1544                if (len < buflen) {
1545                        buflen=len;
1546                        buf=p;
1547                }
1548#endif /* __UCLIBC_HAS_IPV6__ */
1549
1550                if (buflen < 80)
1551                        return ERANGE;
1552
1553                __open_etc_hosts(&fp);
1554                if (fp == NULL) {
1555                        result=NULL;
1556                        return errno;
1557                }
1558        }
1559
1560        *h_errnop=HOST_NOT_FOUND;
1561        if (fp == NULL) {
1562                return ret;
1563        }
1564        while (fgets(buf, buflen, fp)) {
1565                if ((cp = strchr(buf, '#')))
1566                        *cp = '\0';
1567                DPRINTF("Looking at: %s\n", buf);
1568                aliases = 0;
1569
1570                cp = buf;
1571                while (*cp) {
1572                        while (*cp && isspace(*cp))
1573                                *cp++ = '\0';
1574                        if (!*cp)
1575                                continue;
1576                        if (aliases < (2+MAX_ALIASES))
1577                                alias[aliases++] = cp;
1578                        while (*cp && !isspace(*cp))
1579                                cp++;
1580                }
1581                alias[aliases] = 0;
1582
1583                if (aliases < 2)
1584                        continue; /* syntax error really */
1585               
1586                if (action==GETHOSTENT) {
1587                        /* Return whatever the next entry happens to be. */
1588                        break;
1589                } else if (action==GET_HOSTS_BYADDR) {
1590                        if (strcmp(name, alias[0]) != 0)
1591                                continue;
1592                } else {
1593                        /* GET_HOSTS_BYNAME */
1594                        for (i = 1; i < aliases; i++)
1595                                if (strcasecmp(name, alias[i]) == 0)
1596                                        break;
1597                        if (i >= aliases)
1598                                continue;
1599                }
1600
1601                if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
1602                        DPRINTF("Found INET\n");
1603                        addr_list[0] = in;
1604                        addr_list[1] = 0;
1605                        result_buf->h_name = alias[1];
1606                        result_buf->h_addrtype = AF_INET;
1607                        result_buf->h_length = sizeof(*in);
1608                        result_buf->h_addr_list = (char**) addr_list;
1609                        result_buf->h_aliases = alias + 2;
1610                        *result=result_buf;
1611                        ret=NETDB_SUCCESS;
1612#ifdef __UCLIBC_HAS_IPV6__
1613        } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
1614                        DPRINTF("Found INET6\n");
1615                        addr_list6[0] = in6;
1616                        addr_list6[1] = 0;
1617                        result_buf->h_name = alias[1];
1618                        result_buf->h_addrtype = AF_INET6;
1619                        result_buf->h_length = sizeof(*in6);
1620                        result_buf->h_addr_list = (char**) addr_list6;
1621                        result_buf->h_aliases = alias + 2;
1622                        *result=result_buf;
1623                        ret=NETDB_SUCCESS;
1624#endif /* __UCLIBC_HAS_IPV6__ */
1625                } else {
1626                        DPRINTF("Error\n");
1627                        ret=TRY_AGAIN;
1628                        break; /* bad ip address */
1629        }
1630       
1631                if (action!=GETHOSTENT) {
1632                        sl_fclose(FIL__, __LINE__, fp);
1633                }
1634                return ret;
1635        }
1636        if (action!=GETHOSTENT) {
1637                sl_fclose(FIL__, __LINE__, fp);
1638        }
1639        return ret;
1640}
1641
1642/*
1643 *      we currently read formats not quite the same as that on normal
1644 *      unix systems, we can have a list of nameservers after the keyword.
1645 */
1646int __get_hosts_byname_r(const char * name, int type,
1647                            struct hostent * result_buf,
1648                            char * buf, size_t buflen,
1649                            struct hostent ** result,
1650                            int * h_errnop)
1651{
1652        return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME, result_buf, buf, buflen, result, h_errnop));
1653}
1654
1655static int __open_nameservers(void)
1656{
1657        FILE *fp;
1658        int i;
1659#define RESOLV_ARGS 5
1660        char szBuffer[128], *p, *argv[RESOLV_ARGS];
1661        int argc;
1662
1663        SH_MUTEX_LOCK(resolv_lock);
1664        if (__nameservers > 0) {
1665          goto the_end;
1666        }
1667
1668        if ((fp = fopen("/etc/resolv.conf", "r")) ||
1669                        (fp = fopen("/etc/config/resolv.conf", "r"))) {
1670
1671                while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1672
1673                        for (p = szBuffer; *p && isspace(*p); p++)
1674                                /* skip white space */;
1675                        if (*p == '\0' || *p == '\n' || *p == '#') /* skip comments etc */
1676                                continue;
1677                        argc = 0;
1678                        while (*p && argc < RESOLV_ARGS) {
1679                                argv[argc++] = p;
1680                                while (*p && !isspace(*p) && *p != '\n')
1681                                        p++;
1682                                while (*p && (isspace(*p) || *p == '\n')) /* remove spaces */
1683                                        *p++ = '\0';
1684                        }
1685
1686                        if (strcmp(argv[0], "nameserver") == 0) {
1687                                for (i = 1; i < argc && __nameservers < MAX_SERVERS; i++) {
1688                                        __nameserver[__nameservers++] = strdup(argv[i]);
1689                                        DPRINTF("adding nameserver %s\n", argv[i]);
1690                                }
1691                        }
1692
1693                        /* domain and search are mutually exclusive, the last one wins */
1694                        if (strcmp(argv[0],"domain")==0 || strcmp(argv[0],"search")==0) {
1695                                while (__searchdomains > 0) {
1696                                        free(__searchdomain[--__searchdomains]);
1697                                        __searchdomain[__searchdomains] = NULL;
1698                                }
1699                                for (i=1; i < argc && __searchdomains < MAX_SEARCH; i++) {
1700                                        __searchdomain[__searchdomains++] = strdup(argv[i]);
1701                                        DPRINTF("adding search %s\n", argv[i]);
1702                                }
1703                        }
1704                }
1705                sl_fclose(FIL__, __LINE__, fp);
1706        } else {
1707            DPRINTF("failed to open %s\n", "resolv.conf");
1708        }
1709        DPRINTF("nameservers = %d\n", __nameservers);
1710 the_end:
1711        ; /* 'label at end of compound statement' */
1712        SH_MUTEX_UNLOCK(resolv_lock);
1713        /* cppcheck-suppress resourceLeak */
1714        return 0;
1715}
1716
1717static int sh_gethostbyname_r(const char * name,
1718                            struct hostent * result_buf,
1719                            char * buf, size_t buflen,
1720                            struct hostent ** result,
1721                            int * h_errnop)
1722{
1723        struct in_addr *in;
1724        struct in_addr **addr_list;
1725        unsigned char *packet;
1726        struct resolv_answer a;
1727        int i;
1728        int nest = 0;
1729        int __nameserversXX;
1730        char ** __nameserverXX;
1731
1732        DPRINTF("sh_gethostbyname_r: /%s/\n", name);
1733        __open_nameservers();
1734
1735        *result=NULL;
1736        if (!name)
1737                return EINVAL;
1738
1739        /* do /etc/hosts first */
1740        if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
1741                                  buf, buflen, result, h_errnop))==0)
1742                return i;
1743        switch (*h_errnop) {
1744                case HOST_NOT_FOUND:
1745                case NO_ADDRESS:
1746                        break;
1747                case NETDB_INTERNAL:
1748                        if (errno == ENOENT) {
1749                            break;
1750                        }
1751                        /* else fall through */
1752                default:
1753                        return i;
1754        }
1755
1756        DPRINTF("Nothing found in /etc/hosts\n");
1757
1758        *h_errnop = NETDB_INTERNAL;
1759        if (buflen < sizeof(*in))
1760                return ERANGE;
1761        in=(struct in_addr*)buf;
1762        buf+=sizeof(*in);
1763        buflen-=sizeof(*in);
1764
1765        if (buflen < sizeof(*addr_list)*2)
1766                return ERANGE;
1767        addr_list=(struct in_addr**)buf;
1768        buf+=sizeof(*addr_list)*2;
1769        buflen-=sizeof(*addr_list)*2;
1770
1771        addr_list[0] = in;
1772        addr_list[1] = 0;
1773       
1774        if (buflen<256)
1775                return ERANGE;
1776        strncpy(buf, name, buflen-1);
1777
1778        /* First check if this is already an address */
1779        if (inet_aton(name, in)) {
1780            result_buf->h_name = buf;
1781            result_buf->h_addrtype = AF_INET;
1782            result_buf->h_length = sizeof(*in);
1783            result_buf->h_addr_list = (char **) addr_list;
1784            *result=result_buf;
1785            *h_errnop = NETDB_SUCCESS;
1786            return NETDB_SUCCESS;
1787        }
1788
1789        for (;;) {
1790
1791        SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1792        __nameserversXX=__nameservers;
1793        __nameserverXX=__nameserver;
1794        SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1795                i = __dns_lookup(buf, T_A, __nameserversXX, __nameserverXX, &packet, &a);
1796
1797                if (i < 0) {
1798                        *h_errnop = HOST_NOT_FOUND;
1799                        DPRINTF("__dns_lookup\n");
1800                        return TRY_AGAIN;
1801                }
1802
1803                strncpy(buf, a.dotted, buflen-1);
1804                free(a.dotted);
1805
1806                if (a.atype == T_CNAME) {               /* CNAME */
1807                        DPRINTF("Got a CNAME in gethostbyname()\n");
1808                        i = __decode_dotted(packet, a.rdoffset, buf, buflen);
1809                        free(packet);
1810
1811                        if (i < 0) {
1812                                *h_errnop = NO_RECOVERY;
1813                                DPRINTF("__decode_dotted\n");
1814                                return -1;
1815                        }
1816                        if (++nest > MAX_RECURSE) {
1817                                *h_errnop = NO_RECOVERY;
1818                                DPRINTF("recursion\n");
1819                                return -1;
1820                        }
1821                        continue;
1822                } else if (a.atype == T_A) {    /* ADDRESS */
1823                        memcpy(in, a.rdata, sizeof(*in));
1824                        result_buf->h_name = buf;
1825                        result_buf->h_addrtype = AF_INET;
1826                        result_buf->h_length = sizeof(*in);
1827                        result_buf->h_addr_list = (char **) addr_list;
1828                        free(packet);
1829                        break;
1830                } else {
1831                        free(packet);
1832                        *h_errnop=HOST_NOT_FOUND;
1833                        DPRINTF("host_not_found\n");
1834                        return TRY_AGAIN;
1835                }
1836        }
1837
1838        *result=result_buf;
1839        *h_errnop = NETDB_SUCCESS;
1840        return NETDB_SUCCESS;
1841}
1842
1843struct hostent * sh_gethostbyname(const char *name)
1844{
1845        static struct hostent h;
1846        static char buf[sizeof(struct in_addr) +
1847                        sizeof(struct in_addr *)*2 +
1848                        sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
1849        struct hostent *hp;
1850       
1851        DPRINTF("sh_gethostbyname: /%s/\n", name);
1852        sh_gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
1853        return hp;
1854}
1855
1856static int __get_hosts_byaddr_r(const char * addr, int len, int type,
1857                            struct hostent * result_buf,
1858                            char * buf, size_t buflen,
1859                            struct hostent ** result,
1860                            int * h_errnop)
1861{
1862#ifndef __UCLIBC_HAS_IPV6__
1863        char    ipaddr[INET_ADDRSTRLEN];
1864#else
1865        char    ipaddr[INET6_ADDRSTRLEN];
1866#endif /* __UCLIBC_HAS_IPV6__ */
1867
1868    switch (type) {
1869        case AF_INET:
1870                if (len != sizeof(struct in_addr))
1871                        return 0;
1872                break;
1873#ifdef __UCLIBC_HAS_IPV6__
1874        case AF_INET6:
1875                if (len != sizeof(struct in6_addr))
1876                        return 0;
1877                break;
1878#endif /* __UCLIBC_HAS_IPV6__ */
1879        default:
1880                return 0;
1881        }
1882
1883        inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1884
1885        return(__read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR, 
1886                    result_buf, buf, buflen, result, h_errnop));
1887}
1888
1889static int sh_gethostbyaddr_r (const void *addr, socklen_t len, int type,
1890                            struct hostent * result_buf,
1891                            char * buf, size_t buflen,
1892                            struct hostent ** result,
1893                            int * h_errnop)
1894
1895{
1896        struct in_addr *in;
1897        struct in_addr **addr_list;
1898#ifdef __UCLIBC_HAS_IPV6__
1899        char *qp;
1900        size_t plen;
1901        struct in6_addr *in6;
1902        struct in6_addr **addr_list6;
1903#endif /* __UCLIBC_HAS_IPV6__ */
1904        unsigned char *packet;
1905        struct resolv_answer a;
1906        int i;
1907        int nest = 0;
1908        int __nameserversXX;
1909        char ** __nameserverXX;
1910
1911        DPRINTF("sh_gethostbyaddr_r called\n");
1912        *result=NULL;
1913        if (!addr)
1914                return EINVAL;
1915       
1916        switch (type) {
1917                case AF_INET:
1918                        if (len != sizeof(struct in_addr))
1919                                return EINVAL;
1920                        break;
1921#ifdef __UCLIBC_HAS_IPV6__
1922                case AF_INET6:
1923                        if (len != sizeof(struct in6_addr))
1924                                return EINVAL;
1925                        break;
1926#endif /* __UCLIBC_HAS_IPV6__ */
1927                default:
1928                        return EINVAL;
1929        }
1930
1931        /* do /etc/hosts first */
1932        if ((i=__get_hosts_byaddr_r(addr, len, type, result_buf,
1933                                  buf, buflen, result, h_errnop))==0)
1934                return i;
1935        switch (*h_errnop) {
1936                case HOST_NOT_FOUND:
1937                case NO_ADDRESS:
1938                        break;
1939                default:
1940                        return i;
1941        }
1942
1943        __open_nameservers();
1944
1945#ifdef __UCLIBC_HAS_IPV6__
1946        qp=buf;
1947        plen=buflen;
1948#endif /* __UCLIBC_HAS_IPV6__ */
1949
1950        *h_errnop = NETDB_INTERNAL;
1951        if (buflen < sizeof(*in))
1952                return ERANGE;
1953        in=(struct in_addr*)buf;
1954        buf+=sizeof(*in);
1955        buflen-=sizeof(*in);
1956
1957        if (buflen < sizeof(*addr_list)*2)
1958                return ERANGE;
1959        addr_list=(struct in_addr**)buf;
1960        buf+=sizeof(*addr_list)*2;
1961        buflen-=sizeof(*addr_list)*2;
1962
1963#ifdef __UCLIBC_HAS_IPV6__
1964        if (plen < sizeof(*in6))
1965                return ERANGE;
1966        in6=(struct in6_addr*)qp;
1967        qp+=sizeof(*in6);
1968        plen-=sizeof(*in6);
1969
1970        if (plen < sizeof(*addr_list6)*2)
1971                return ERANGE;
1972        addr_list6=(struct in6_addr**)qp;
1973        qp+=sizeof(*addr_list6)*2;
1974        plen-=sizeof(*addr_list6)*2;
1975
1976        if (plen < buflen) {
1977                buflen=plen;
1978                buf=qp;
1979        }
1980#endif /* __UCLIBC_HAS_IPV6__ */
1981
1982        if (buflen<256)
1983                return ERANGE;
1984
1985        if(type == AF_INET) {
1986                const unsigned char *tmp_addr = (const unsigned char *)addr;
1987
1988                memcpy(&in->s_addr, addr, len);
1989
1990                addr_list[0] = in;
1991
1992                sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
1993                        tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
1994#ifdef __UCLIBC_HAS_IPV6__
1995        } else {
1996                memcpy(in6->s6_addr, addr, len);
1997
1998                addr_list6[0] = in6;
1999                qp = buf;
2000
2001                for (i = len - 1; i >= 0; i--) {
2002                        qp += sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
2003                                (in6->s6_addr[i] >> 4) & 0xf);
2004        }
2005        strcpy(qp, "ip6.int");
2006#endif /* __UCLIBC_HAS_IPV6__ */
2007        }
2008
2009        addr_list[1] = 0;
2010
2011        for (;;) {
2012
2013        SH_MUTEX_LOCK_UNSAFE(resolv_lock);
2014        __nameserversXX=__nameservers;
2015        __nameserverXX=__nameserver;
2016        SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
2017                i = __dns_lookup(buf, T_PTR, __nameserversXX, __nameserverXX, &packet, &a);
2018
2019                if (i < 0) {
2020                        *h_errnop = HOST_NOT_FOUND;
2021                        return TRY_AGAIN;
2022                }
2023
2024                strncpy(buf, a.dotted, buflen-1);
2025                free(a.dotted);
2026
2027                if (a.atype == T_CNAME) {               /* CNAME */
2028                        DPRINTF("Got a CNAME in gethostbyaddr()\n");
2029                        i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2030                        free(packet);
2031
2032                        if (i < 0) {
2033                                *h_errnop = NO_RECOVERY;
2034                                return -1;
2035                        }
2036                        if (++nest > MAX_RECURSE) {
2037                                *h_errnop = NO_RECOVERY;
2038                                return -1;
2039                        }
2040                        continue;
2041                } else if (a.atype == T_PTR) {  /* ADDRESS */
2042                        i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2043                        free(packet);
2044
2045                        result_buf->h_name = buf;
2046                        result_buf->h_addrtype = type;
2047
2048                        if(type == AF_INET) {
2049                                result_buf->h_length = sizeof(*in);
2050#ifdef __UCLIBC_HAS_IPV6__
2051                        } else {
2052                                result_buf->h_length = sizeof(*in6);
2053#endif /* __UCLIBC_HAS_IPV6__ */
2054                }
2055
2056                        result_buf->h_addr_list = (char **) addr_list;
2057                        break;
2058                } else {
2059                        free(packet);
2060                        *h_errnop = NO_ADDRESS;
2061                        return TRY_AGAIN;
2062                }
2063        }
2064
2065        *result=result_buf;
2066        *h_errnop = NETDB_SUCCESS;
2067        return NETDB_SUCCESS;
2068}
2069
2070struct hostent * sh_gethostbyaddr (const void *addr, socklen_t len, int type)
2071{
2072        static struct hostent h;
2073        static char buf[
2074#ifndef __UCLIBC_HAS_IPV6__
2075                sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2076#else
2077                sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2078#endif /* __UCLIBC_HAS_IPV6__ */
2079                sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
2080        struct hostent *hp;
2081
2082        DPRINTF("sh_gethostbyaddr called\n");
2083        sh_gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
2084       
2085        return hp;
2086}
2087
2088/* NEED_STATIC_LIBS */
2089#else
2090
2091/* include something to avoid empty compilation unit */
2092#include <stdio.h>
2093
2094#endif
2095
Note: See TracBrowser for help on using the repository browser.