source: trunk/src/sh_static.c@ 94

Last change on this file since 94 was 22, checked in by rainer, 19 years ago

Minor code revisions.

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