source: trunk/src/sh_static.c@ 165

Last change on this file since 165 was 150, checked in by katerina, 17 years ago

Fix more 'label at end of compound statement' (closes ticket #86).

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